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 #include <plugin/slave/queue_consumer.h>
00023 #include <drizzled/errmsg_print.h>
00024 #include <drizzled/execute.h>
00025 #include <drizzled/message/transaction.pb.h>
00026 #include <drizzled/message/statement_transform.h>
00027 #include <drizzled/sql/result_set.h>
00028 #include <string>
00029 #include <vector>
00030 #include <boost/thread.hpp>
00031 #include <boost/lexical_cast.hpp>
00032 #include <google/protobuf/text_format.h>
00033
00034 using namespace std;
00035 using namespace drizzled;
00036
00037 namespace slave
00038 {
00039
00040 bool QueueConsumer::init()
00041 {
00042 setApplierState("", true);
00043 return true;
00044 }
00045
00046
00047 void QueueConsumer::shutdown()
00048 {
00049 setApplierState(getErrorMessage(), false);
00050 }
00051
00052
00053 bool QueueConsumer::process()
00054 {
00055 for (size_t index= 0; index < _master_ids.size(); index++)
00056 {
00057
00058
00059
00060 const string master_id= boost::lexical_cast<string>(_master_ids[index]);
00061
00062 if (not processSingleMaster(master_id))
00063 return false;
00064 }
00065
00066 return true;
00067 }
00068
00069 bool QueueConsumer::processSingleMaster(const string &master_id)
00070 {
00071 TrxIdList completedTransactionIds;
00072
00073 getListOfCompletedTransactions(master_id, completedTransactionIds);
00074
00075 for (size_t x= 0; x < completedTransactionIds.size(); x++)
00076 {
00077 string commit_id;
00078 string originating_server_uuid;
00079 uint64_t originating_commit_id= 0;
00080 uint64_t trx_id= completedTransactionIds[x];
00081
00082 vector<string> aggregate_sql;
00083 vector<string> segmented_sql;
00084
00085 message::Transaction transaction;
00086 uint32_t segment_id= 1;
00087
00088 while (getMessage(transaction, commit_id, master_id, trx_id, originating_server_uuid,
00089 originating_commit_id, segment_id++))
00090 {
00091 convertToSQL(transaction, aggregate_sql, segmented_sql);
00092 transaction.Clear();
00093 }
00094
00095
00096
00097
00098
00099
00100 assert((not commit_id.empty()) && (commit_id != "0"));
00101 assert(segmented_sql.empty());
00102
00103 if (not aggregate_sql.empty())
00104 {
00105
00106
00107
00108 vector<string>::iterator agg_iter;
00109 for (agg_iter= aggregate_sql.begin(); agg_iter != aggregate_sql.end(); ++agg_iter)
00110 {
00111 string &sql= *agg_iter;
00112 string::iterator si= sql.begin();
00113 for (; si != sql.end(); ++si)
00114 {
00115 if (*si == '\"')
00116 {
00117 si= sql.insert(si, '\\');
00118 ++si;
00119 }
00120 else if (*si == '\\')
00121 {
00122 si= sql.insert(si, '\\');
00123 ++si;
00124 si= sql.insert(si, '\\');
00125 ++si;
00126 si= sql.insert(si, '\\');
00127 ++si;
00128 }
00129 else if (*si == ';')
00130 {
00131 si= sql.insert(si, '\\');
00132 ++si;
00133 }
00134 }
00135 }
00136 }
00137
00138 if (not executeSQLWithCommitId(aggregate_sql, commit_id,
00139 originating_server_uuid,
00140 originating_commit_id,
00141 master_id))
00142 {
00143 if (_ignore_errors)
00144 {
00145 clearErrorState();
00146
00147
00148 vector<string> sql;
00149 string tmp("UPDATE `sys_replication`.`applier_state`"
00150 " SET `last_applied_commit_id` = ");
00151 tmp.append(commit_id);
00152 tmp.append(" WHERE `master_id` = ");
00153 tmp.append(master_id);
00154 sql.push_back(tmp);
00155 executeSQL(sql);
00156 }
00157 else
00158 {
00159 return false;
00160 }
00161 }
00162
00163 if (not deleteFromQueue(master_id, trx_id))
00164 {
00165 return false;
00166 }
00167 }
00168
00169 return true;
00170 }
00171
00172
00173 bool QueueConsumer::getMessage(message::Transaction &transaction,
00174 string &commit_id,
00175 const string &master_id,
00176 uint64_t trx_id,
00177 string &originating_server_uuid,
00178 uint64_t &originating_commit_id,
00179 uint32_t segment_id)
00180 {
00181 string sql("SELECT `msg`, `commit_order`, `originating_server_uuid`, "
00182 "`originating_commit_id` FROM `sys_replication`.`queue`"
00183 " WHERE `trx_id` = ");
00184 sql.append(boost::lexical_cast<string>(trx_id));
00185 sql.append(" AND `seg_id` = ", 16);
00186 sql.append(boost::lexical_cast<string>(segment_id));
00187 sql.append(" AND `master_id` = ", 19),
00188 sql.append(master_id);
00189
00190 sql::ResultSet result_set(4);
00191 Execute execute(*(_session.get()), true);
00192
00193 execute.run(sql, result_set);
00194
00195 assert(result_set.getMetaData().getColumnCount() == 4);
00196
00197
00198 uint32_t found_rows= 0;
00199 while (result_set.next())
00200 {
00201 string msg= result_set.getString(0);
00202 string com_id= result_set.getString(1);
00203 string orig_server_uuid= result_set.getString(2);
00204 string orig_commit_id= result_set.getString(3);
00205
00206 if ((msg == "") || (found_rows == 1))
00207 break;
00208
00209
00210 assert(result_set.isNull(0) == false);
00211 assert(result_set.isNull(1) == false);
00212 assert(result_set.isNull(2) == false);
00213 assert(result_set.isNull(3) == false);
00214
00215
00216 google::protobuf::TextFormat::ParseFromString(msg, &transaction);
00217
00218 commit_id= com_id;
00219 originating_server_uuid= orig_server_uuid;
00220 originating_commit_id= boost::lexical_cast<uint64_t>(orig_commit_id);
00221 found_rows++;
00222 }
00223
00224 if (found_rows == 0)
00225 return false;
00226
00227 return true;
00228 }
00229
00230 bool QueueConsumer::getListOfCompletedTransactions(const string &master_id,
00231 TrxIdList &list)
00232 {
00233 Execute execute(*(_session.get()), true);
00234
00235 string sql("SELECT `trx_id` FROM `sys_replication`.`queue`"
00236 " WHERE `commit_order` IS NOT NULL AND `commit_order` > 0"
00237 " AND `master_id` = "
00238 + master_id
00239 + " ORDER BY `commit_order` ASC");
00240
00241
00242 sql::ResultSet result_set(1);
00243
00244 execute.run(sql, result_set);
00245
00246 assert(result_set.getMetaData().getColumnCount() == 1);
00247
00248 while (result_set.next())
00249 {
00250 assert(result_set.isNull(0) == false);
00251 string value= result_set.getString(0);
00252
00253
00254 if (value != "")
00255 {
00256 list.push_back(boost::lexical_cast<uint64_t>(result_set.getString(0)));
00257 }
00258 }
00259
00260 return true;
00261 }
00262
00263
00264 bool QueueConsumer::convertToSQL(const message::Transaction &transaction,
00265 vector<string> &aggregate_sql,
00266 vector<string> &segmented_sql)
00267 {
00268 if (transaction.has_event())
00269 return true;
00270
00271 size_t num_statements= transaction.statement_size();
00272
00273
00274
00275
00276
00277
00278
00279
00280 for (size_t idx= 0; idx < num_statements; idx++)
00281 {
00282 const message::Statement &statement= transaction.statement(idx);
00283
00284
00285 if (statement.type() == message::Statement::ROLLBACK)
00286 {
00287 assert(idx == (num_statements - 1));
00288 aggregate_sql.clear();
00289 segmented_sql.clear();
00290 break;
00291 }
00292
00293 switch (statement.type())
00294 {
00295
00296 case message::Statement::TRUNCATE_TABLE:
00297 case message::Statement::CREATE_SCHEMA:
00298 case message::Statement::ALTER_SCHEMA:
00299 case message::Statement::DROP_SCHEMA:
00300 case message::Statement::CREATE_TABLE:
00301 case message::Statement::ALTER_TABLE:
00302 case message::Statement::DROP_TABLE:
00303 case message::Statement::RAW_SQL:
00304 {
00305 segmented_sql.push_back("COMMIT");
00306 break;
00307 }
00308
00309
00310 case message::Statement::ROLLBACK_STATEMENT:
00311 {
00312 segmented_sql.clear();
00313 continue;
00314 }
00315
00316 default:
00317 {
00318 break;
00319 }
00320 }
00321
00322 if (message::transformStatementToSql(statement, segmented_sql,
00323 message::DRIZZLE, true))
00324 {
00325 return false;
00326 }
00327
00328 if (isEndStatement(statement))
00329 {
00330 aggregate_sql.insert(aggregate_sql.end(),
00331 segmented_sql.begin(),
00332 segmented_sql.end());
00333 segmented_sql.clear();
00334 }
00335 }
00336
00337 return true;
00338 }
00339
00340
00341 bool QueueConsumer::isEndStatement(const message::Statement &statement)
00342 {
00343 switch (statement.type())
00344 {
00345 case (message::Statement::INSERT):
00346 {
00347 const message::InsertData &data= statement.insert_data();
00348 if (not data.end_segment())
00349 return false;
00350 break;
00351 }
00352 case (message::Statement::UPDATE):
00353 {
00354 const message::UpdateData &data= statement.update_data();
00355 if (not data.end_segment())
00356 return false;
00357 break;
00358 }
00359 case (message::Statement::DELETE):
00360 {
00361 const message::DeleteData &data= statement.delete_data();
00362 if (not data.end_segment())
00363 return false;
00364 break;
00365 }
00366 default:
00367 return true;
00368 }
00369 return true;
00370 }
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380 void QueueConsumer::setApplierState(const string &err_msg, bool status)
00381 {
00382 vector<string> statements;
00383 string sql;
00384 string msg(err_msg);
00385
00386 if (not status)
00387 {
00388 sql= "UPDATE `sys_replication`.`applier_state` SET `status` = 'STOPPED'";
00389 }
00390 else
00391 {
00392 sql= "UPDATE `sys_replication`.`applier_state` SET `status` = 'RUNNING'";
00393 }
00394
00395 sql.append(", `error_msg` = '", 17);
00396
00397
00398 string::iterator it;
00399 for (it= msg.begin(); it != msg.end(); ++it)
00400 {
00401 if (*it == '\'')
00402 {
00403 it= msg.insert(it, '\'');
00404 ++it;
00405 }
00406 else if (*it == ';')
00407 {
00408 it= msg.insert(it, '\\');
00409 ++it;
00410 }
00411 }
00412
00413 sql.append(msg);
00414 sql.append("'", 1);
00415
00416 statements.push_back(sql);
00417 executeSQL(statements);
00418 }
00419
00420
00421 bool QueueConsumer::executeSQLWithCommitId(vector<string> &sql,
00422 const string &commit_id,
00423 const string &originating_server_uuid,
00424 uint64_t originating_commit_id,
00425 const string &master_id)
00426 {
00427 string tmp("UPDATE `sys_replication`.`applier_state`"
00428 " SET `last_applied_commit_id` = ");
00429 tmp.append(commit_id);
00430 tmp.append(", `originating_server_uuid` = '");
00431 tmp.append(originating_server_uuid);
00432 tmp.append("' , `originating_commit_id` = ");
00433 tmp.append(boost::lexical_cast<string>(originating_commit_id));
00434
00435 tmp.append(" WHERE `master_id` = ");
00436 tmp.append(master_id);
00437
00438 sql.push_back(tmp);
00439
00440 _session->setOriginatingServerUUID(originating_server_uuid);
00441 _session->setOriginatingCommitID(originating_commit_id);
00442
00443 return executeSQL(sql);
00444 }
00445
00446
00447 bool QueueConsumer::deleteFromQueue(const string &master_id, uint64_t trx_id)
00448 {
00449 string sql("DELETE FROM `sys_replication`.`queue` WHERE `trx_id` = ");
00450 sql.append(boost::lexical_cast<std::string>(trx_id));
00451
00452 sql.append(" AND `master_id` = ");
00453 sql.append(master_id);
00454
00455 vector<string> sql_vect;
00456 sql_vect.push_back(sql);
00457
00458 return executeSQL(sql_vect);
00459 }
00460
00461 }