00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <config.h>
00022
00023 #include <plugin/slave/queue_producer.h>
00024 #include <drizzled/errmsg_print.h>
00025 #include <drizzled/sql/result_set.h>
00026 #include <drizzled/execute.h>
00027 #include <drizzled/gettext.h>
00028 #include <drizzled/message/transaction.pb.h>
00029 #include <boost/lexical_cast.hpp>
00030 #include <google/protobuf/text_format.h>
00031 #include <string>
00032 #include <vector>
00033
00034 using namespace std;
00035 using namespace drizzled;
00036
00037 namespace slave
00038 {
00039
00040 QueueProducer::~QueueProducer()
00041 {
00042 if (_is_connected)
00043 closeConnection();
00044 }
00045
00046 bool QueueProducer::init()
00047 {
00048 setIOState("", true);
00049 return reconnect(true);
00050 }
00051
00052 bool QueueProducer::process()
00053 {
00054 if (_saved_max_commit_id == 0)
00055 {
00056 if (not queryForMaxCommitId(&_saved_max_commit_id))
00057 {
00058 if (_last_return == DRIZZLE_RETURN_LOST_CONNECTION)
00059 {
00060 if (reconnect(false))
00061 {
00062 return true;
00063 }
00064 else
00065 {
00066 _last_error_message= "Master offline";
00067 return false;
00068 }
00069 }
00070 else
00071 {
00072 return false;
00073 }
00074 }
00075 }
00076
00077
00078 enum drizzled::error_t err;
00079 while ((err= (queryForReplicationEvents(_saved_max_commit_id))) == EE_OK)
00080 {}
00081
00082 if (err == ER_YES)
00083 {
00084 if (_last_return == DRIZZLE_RETURN_LOST_CONNECTION)
00085 {
00086 if (reconnect(false))
00087 {
00088 return true;
00089 }
00090 else
00091 {
00092 _last_error_message= "Master offline";
00093 return false;
00094 }
00095 }
00096 else
00097 {
00098 return false;
00099 }
00100 }
00101
00102 return true;
00103 }
00104
00105 void QueueProducer::shutdown()
00106 {
00107 setIOState(_last_error_message, false);
00108 if (_is_connected)
00109 closeConnection();
00110 }
00111
00112 bool QueueProducer::reconnect(bool initial_connection)
00113 {
00114 if (not initial_connection)
00115 {
00116 errmsg_printf(error::ERROR, _("Lost connection to master. Reconnecting."));
00117 }
00118
00119 _is_connected= false;
00120 _last_return= DRIZZLE_RETURN_OK;
00121 _last_error_message.clear();
00122 boost::posix_time::seconds duration(_seconds_between_reconnects);
00123
00124 uint32_t attempts= 1;
00125
00126 while (not openConnection())
00127 {
00128 if (attempts++ == _max_reconnects)
00129 break;
00130 boost::this_thread::sleep(duration);
00131 }
00132
00133 return _is_connected;
00134 }
00135
00136 bool QueueProducer::openConnection()
00137 {
00138 if ((_drizzle= drizzle_create()) == NULL)
00139 {
00140 _last_return= DRIZZLE_RETURN_INTERNAL_ERROR;
00141 _last_error_message= "Replication slave: ";
00142 _last_error_message.append(drizzle_error(_drizzle));
00143 errmsg_printf(error::ERROR, _("%s"), _last_error_message.c_str());
00144 return false;
00145 }
00146
00147 if ((_connection= drizzle_con_create(_drizzle)) == NULL)
00148 {
00149 _last_return= DRIZZLE_RETURN_INTERNAL_ERROR;
00150 _last_error_message= "Replication slave: ";
00151 _last_error_message.append(drizzle_error(_drizzle));
00152 errmsg_printf(error::ERROR, _("%s"), _last_error_message.c_str());
00153 return false;
00154 }
00155
00156 drizzle_con_set_tcp(_connection, _master_host.c_str(), _master_port);
00157 drizzle_con_set_auth(_connection, _master_user.c_str(), _master_pass.c_str());
00158
00159 drizzle_return_t ret= drizzle_con_connect(_connection);
00160
00161 if (ret != DRIZZLE_RETURN_OK)
00162 {
00163 _last_return= ret;
00164 _last_error_message= "Replication slave: ";
00165 _last_error_message.append(drizzle_error(_drizzle));
00166 errmsg_printf(error::ERROR, _("%s"), _last_error_message.c_str());
00167 return false;
00168 }
00169
00170 _is_connected= true;
00171
00172 return true;
00173 }
00174
00175 bool QueueProducer::closeConnection()
00176 {
00177 drizzle_return_t ret;
00178 drizzle_result_st result;
00179
00180 _is_connected= false;
00181
00182 if (drizzle_quit(_connection, &result, &ret) == NULL)
00183 {
00184 _last_return= ret;
00185 drizzle_result_free(&result);
00186 return false;
00187 }
00188
00189 drizzle_result_free(&result);
00190
00191 return true;
00192 }
00193
00194 bool QueueProducer::queryForMaxCommitId(uint64_t *max_commit_id)
00195 {
00196
00197
00198
00199
00200
00201
00202
00203 string sql("SELECT MAX(x.cid) FROM"
00204 " (SELECT MAX(`commit_order`) AS cid FROM `sys_replication`.`queue`"
00205 " WHERE `master_id` = "
00206 + boost::lexical_cast<string>(masterId())
00207 + " UNION ALL SELECT `last_applied_commit_id` AS cid"
00208 + " FROM `sys_replication`.`applier_state` WHERE `master_id` = "
00209 + boost::lexical_cast<string>(masterId())
00210 + ") AS x");
00211
00212 sql::ResultSet result_set(1);
00213 Execute execute(*(_session.get()), true);
00214 execute.run(sql, result_set);
00215 assert(result_set.getMetaData().getColumnCount() == 1);
00216
00217
00218 uint32_t found_rows= 0;
00219 while (result_set.next())
00220 {
00221 string value= result_set.getString(0);
00222
00223 if ((value == "") || (found_rows == 1))
00224 break;
00225
00226 assert(result_set.isNull(0) == false);
00227 *max_commit_id= boost::lexical_cast<uint64_t>(value);
00228 found_rows++;
00229 }
00230
00231 if (found_rows == 0)
00232 {
00233 _last_error_message= "Could not determine last committed transaction.";
00234 return false;
00235 }
00236
00237 return true;
00238 }
00239
00240 bool QueueProducer::queryForTrxIdList(uint64_t max_commit_id,
00241 vector<uint64_t> &list)
00242 {
00243 (void)list;
00244 string sql("SELECT `id` FROM `data_dictionary`.`sys_replication_log`"
00245 " WHERE `commit_id` > ");
00246 sql.append(boost::lexical_cast<string>(max_commit_id));
00247 sql.append(" ORDER BY `commit_id` LIMIT 25");
00248
00249 drizzle_return_t ret;
00250 drizzle_result_st result;
00251 drizzle_query_str(_connection, &result, sql.c_str(), &ret);
00252
00253 if (ret != DRIZZLE_RETURN_OK)
00254 {
00255 _last_return= ret;
00256 _last_error_message= "Replication slave: ";
00257 _last_error_message.append(drizzle_error(_drizzle));
00258 errmsg_printf(error::ERROR, _("%s"), _last_error_message.c_str());
00259 drizzle_result_free(&result);
00260 return false;
00261 }
00262
00263 ret= drizzle_result_buffer(&result);
00264
00265 if (ret != DRIZZLE_RETURN_OK)
00266 {
00267 _last_return= ret;
00268 _last_error_message= "Replication slave: ";
00269 _last_error_message.append(drizzle_error(_drizzle));
00270 errmsg_printf(error::ERROR, _("%s"), _last_error_message.c_str());
00271 drizzle_result_free(&result);
00272 return false;
00273 }
00274
00275 drizzle_row_t row;
00276
00277 while ((row= drizzle_row_next(&result)) != NULL)
00278 {
00279 if (row[0])
00280 {
00281 list.push_back(boost::lexical_cast<uint32_t>(row[0]));
00282 }
00283 else
00284 {
00285 _last_return= ret;
00286 _last_error_message= "Replication slave: Unexpected NULL for trx id";
00287 errmsg_printf(error::ERROR, _("%s"), _last_error_message.c_str());
00288 drizzle_result_free(&result);
00289 return false;
00290 }
00291 }
00292
00293 drizzle_result_free(&result);
00294 return true;
00295 }
00296
00297
00298 bool QueueProducer::queueInsert(const char *trx_id,
00299 const char *seg_id,
00300 const char *commit_id,
00301 const char *originating_server_uuid,
00302 const char *originating_commit_id,
00303 const char *msg,
00304 const char *msg_length)
00305 {
00306 message::Transaction message;
00307
00308 message.ParseFromArray(msg, boost::lexical_cast<int>(msg_length));
00309
00310
00311
00312
00313 string sql= "INSERT INTO `sys_replication`.`queue`"
00314 " (`master_id`, `trx_id`, `seg_id`, `commit_order`,"
00315 " `originating_server_uuid`, `originating_commit_id`, `msg`) VALUES (";
00316 sql.append(boost::lexical_cast<string>(masterId()));
00317 sql.append(", ", 2);
00318 sql.append(trx_id);
00319 sql.append(", ", 2);
00320 sql.append(seg_id);
00321 sql.append(", ", 2);
00322 sql.append(commit_id);
00323 sql.append(", '", 3);
00324 sql.append(originating_server_uuid);
00325 sql.append("' , ", 4);
00326 sql.append(originating_commit_id);
00327 sql.append(", '", 3);
00328
00329
00330
00331
00332
00333
00334
00335 string message_text;
00336 google::protobuf::TextFormat::PrintToString(message, &message_text);
00337
00338
00339
00340
00341 string::iterator it= message_text.begin();
00342 for (; it != message_text.end(); ++it)
00343 {
00344 if (*it == '\"')
00345 {
00346 it= message_text.insert(it, '\\');
00347 ++it;
00348 }
00349 else if (*it == '\'')
00350 {
00351 it= message_text.insert(it, '\\');
00352 ++it;
00353 it= message_text.insert(it, '\\');
00354 ++it;
00355 }
00356 else if (*it == '\\')
00357 {
00358 it= message_text.insert(it, '\\');
00359 ++it;
00360 it= message_text.insert(it, '\\');
00361 ++it;
00362 it= message_text.insert(it, '\\');
00363 ++it;
00364 }
00365 else if (*it == ';')
00366 {
00367 it= message_text.insert(it, '\\');
00368 ++it;
00369 }
00370 }
00371
00372 sql.append(message_text);
00373 sql.append("')", 2);
00374
00375 vector<string> statements;
00376 statements.push_back(sql);
00377
00378 if (not executeSQL(statements))
00379 {
00380 markInErrorState();
00381 return false;
00382 }
00383
00384 uint64_t tmp_commit_id= boost::lexical_cast<uint64_t>(commit_id);
00385 if (tmp_commit_id > _saved_max_commit_id)
00386 _saved_max_commit_id= tmp_commit_id;
00387
00388 return true;
00389 }
00390
00391
00392 enum drizzled::error_t QueueProducer::queryForReplicationEvents(uint64_t max_commit_id)
00393 {
00394 vector<uint64_t> trx_id_list;
00395
00396 if (not queryForTrxIdList(max_commit_id, trx_id_list))
00397 return ER_YES;
00398
00399 if (trx_id_list.size() == 0)
00400 {
00401 return ER_NO;
00402 }
00403
00404
00405
00406
00407 string sql= "SELECT `id`, `segid`, `commit_id`, `originating_server_uuid`,"
00408 " `originating_commit_id`, `message`, `message_len` "
00409 " FROM `data_dictionary`.`sys_replication_log` WHERE `id` IN (";
00410
00411 for (size_t x= 0; x < trx_id_list.size(); x++)
00412 {
00413 if (x > 0)
00414 sql.append(", ", 2);
00415 sql.append(boost::lexical_cast<string>(trx_id_list[x]));
00416 }
00417
00418 sql.append(")", 1);
00419 sql.append(" ORDER BY `commit_id` ASC");
00420
00421 drizzle_return_t ret;
00422 drizzle_result_st result;
00423 drizzle_query_str(_connection, &result, sql.c_str(), &ret);
00424
00425 if (ret != DRIZZLE_RETURN_OK)
00426 {
00427 _last_return= ret;
00428 _last_error_message= "Replication slave: ";
00429 _last_error_message.append(drizzle_error(_drizzle));
00430 errmsg_printf(error::ERROR, _("%s"), _last_error_message.c_str());
00431 drizzle_result_free(&result);
00432 return ER_YES;
00433 }
00434
00435
00436
00437 ret= drizzle_result_buffer(&result);
00438
00439 if (ret != DRIZZLE_RETURN_OK)
00440 {
00441 _last_return= ret;
00442 _last_error_message= "Replication slave: ";
00443 _last_error_message.append(drizzle_error(_drizzle));
00444 errmsg_printf(error::ERROR, _("%s"), _last_error_message.c_str());
00445 drizzle_result_free(&result);
00446 return ER_YES;
00447 }
00448
00449 drizzle_row_t row;
00450
00451 while ((row= drizzle_row_next(&result)) != NULL)
00452 {
00453 if (not queueInsert(row[0], row[1], row[2], row[3], row[4], row[5], row[6]))
00454 {
00455 errmsg_printf(error::ERROR,
00456 _("Replication slave: Unable to insert into queue."));
00457 drizzle_result_free(&result);
00458 return ER_YES;
00459 }
00460 }
00461
00462 drizzle_result_free(&result);
00463
00464 return EE_OK;
00465 }
00466
00467
00468 void QueueProducer::setIOState(const string &err_msg, bool status)
00469 {
00470 vector<string> statements;
00471 string sql;
00472 string msg(err_msg);
00473
00474 if (not status)
00475 {
00476 sql= "UPDATE `sys_replication`.`io_state` SET `status` = 'STOPPED'";
00477 }
00478 else
00479 {
00480 sql= "UPDATE `sys_replication`.`io_state` SET `status` = 'RUNNING'";
00481 }
00482
00483 sql.append(", `error_msg` = '", 17);
00484
00485
00486 string::iterator it;
00487 for (it= msg.begin(); it != msg.end(); ++it)
00488 {
00489 if (*it == '\'')
00490 {
00491 it= msg.insert(it, '\'');
00492 ++it;
00493 }
00494 else if (*it == ';')
00495 {
00496 it= msg.insert(it, '\\');
00497 ++it;
00498 }
00499 }
00500
00501 sql.append(msg);
00502 sql.append("' WHERE `master_id` = ");
00503 sql.append(boost::lexical_cast<string>(masterId()));
00504
00505 statements.push_back(sql);
00506 executeSQL(statements);
00507 }
00508
00509 }