00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00050 #include <config.h>
00051 #include <drizzled/current_session.h>
00052 #include <drizzled/error.h>
00053 #include <drizzled/gettext.h>
00054 #include <drizzled/probes.h>
00055 #include <drizzled/sql_parse.h>
00056 #include <drizzled/session.h>
00057 #include <drizzled/session/times.h>
00058 #include <drizzled/sql_base.h>
00059 #include <drizzled/replication_services.h>
00060 #include <drizzled/transaction_services.h>
00061 #include <drizzled/transaction_context.h>
00062 #include <drizzled/message/transaction.pb.h>
00063 #include <drizzled/message/statement_transform.h>
00064 #include <drizzled/resource_context.h>
00065 #include <drizzled/lock.h>
00066 #include <drizzled/item/int.h>
00067 #include <drizzled/item/empty_string.h>
00068 #include <drizzled/field/epoch.h>
00069 #include <drizzled/plugin/client.h>
00070 #include <drizzled/plugin/monitored_in_transaction.h>
00071 #include <drizzled/plugin/transactional_storage_engine.h>
00072 #include <drizzled/plugin/xa_resource_manager.h>
00073 #include <drizzled/plugin/xa_storage_engine.h>
00074 #include <drizzled/internal/my_sys.h>
00075 #include <drizzled/statistics_variables.h>
00076 #include <drizzled/system_variables.h>
00077 #include <drizzled/session/transactions.h>
00078
00079 #include <vector>
00080 #include <algorithm>
00081 #include <functional>
00082 #include <google/protobuf/repeated_field.h>
00083
00084 using namespace std;
00085 using namespace google;
00086
00087 namespace drizzled {
00088
00307 static plugin::XaStorageEngine& xa_storage_engine()
00308 {
00309 static plugin::XaStorageEngine& engine= static_cast<plugin::XaStorageEngine&>(*plugin::StorageEngine::findByName("InnoDB"));
00310 return engine;
00311 }
00312
00313 void TransactionServices::registerResourceForStatement(Session& session,
00314 plugin::MonitoredInTransaction *monitored,
00315 plugin::TransactionalStorageEngine *engine)
00316 {
00317 if (session_test_options(&session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
00318 {
00319
00320
00321
00322
00323
00324
00325
00326 registerResourceForTransaction(session, monitored, engine);
00327 }
00328
00329 TransactionContext& trans= session.transaction.stmt;
00330 ResourceContext& resource_context= session.getResourceContext(*monitored, 0);
00331
00332 if (resource_context.isStarted())
00333 return;
00334
00335 assert(monitored->participatesInSqlTransaction());
00336 assert(not monitored->participatesInXaTransaction());
00337
00338 resource_context.setMonitored(monitored);
00339 resource_context.setTransactionalStorageEngine(engine);
00340 trans.registerResource(&resource_context);
00341 trans.no_2pc= true;
00342 }
00343
00344 void TransactionServices::registerResourceForStatement(Session& session,
00345 plugin::MonitoredInTransaction *monitored,
00346 plugin::TransactionalStorageEngine *engine,
00347 plugin::XaResourceManager *resource_manager)
00348 {
00349 if (session_test_options(&session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
00350 {
00351
00352
00353
00354
00355
00356
00357
00358 registerResourceForTransaction(session, monitored, engine, resource_manager);
00359 }
00360
00361 TransactionContext& trans= session.transaction.stmt;
00362 ResourceContext& resource_context= session.getResourceContext(*monitored, 0);
00363
00364 if (resource_context.isStarted())
00365 return;
00366
00367 assert(monitored->participatesInXaTransaction());
00368 assert(monitored->participatesInSqlTransaction());
00369
00370 resource_context.setMonitored(monitored);
00371 resource_context.setTransactionalStorageEngine(engine);
00372 resource_context.setXaResourceManager(resource_manager);
00373 trans.registerResource(&resource_context);
00374 }
00375
00376 void TransactionServices::registerResourceForTransaction(Session& session,
00377 plugin::MonitoredInTransaction *monitored,
00378 plugin::TransactionalStorageEngine *engine)
00379 {
00380 TransactionContext& trans= session.transaction.all;
00381 ResourceContext& resource_context= session.getResourceContext(*monitored, 1);
00382
00383 if (resource_context.isStarted())
00384 return;
00385
00386 session.server_status|= SERVER_STATUS_IN_TRANS;
00387
00388 trans.registerResource(&resource_context);
00389
00390 assert(monitored->participatesInSqlTransaction());
00391 assert(not monitored->participatesInXaTransaction());
00392
00393 resource_context.setMonitored(monitored);
00394 resource_context.setTransactionalStorageEngine(engine);
00395 trans.no_2pc= true;
00396
00397 if (session.transaction.xid_state.xid.is_null())
00398 session.transaction.xid_state.xid.set(session.getQueryId());
00399
00400
00401 if (not session.getResourceContext(*monitored, 0).isStarted())
00402 registerResourceForStatement(session, monitored, engine);
00403 }
00404
00405 void TransactionServices::registerResourceForTransaction(Session& session,
00406 plugin::MonitoredInTransaction *monitored,
00407 plugin::TransactionalStorageEngine *engine,
00408 plugin::XaResourceManager *resource_manager)
00409 {
00410 TransactionContext *trans= &session.transaction.all;
00411 ResourceContext& resource_context= session.getResourceContext(*monitored, 1);
00412
00413 if (resource_context.isStarted())
00414 return;
00415
00416 session.server_status|= SERVER_STATUS_IN_TRANS;
00417
00418 trans->registerResource(&resource_context);
00419
00420 assert(monitored->participatesInSqlTransaction());
00421
00422 resource_context.setMonitored(monitored);
00423 resource_context.setXaResourceManager(resource_manager);
00424 resource_context.setTransactionalStorageEngine(engine);
00425 trans->no_2pc= true;
00426
00427 if (session.transaction.xid_state.xid.is_null())
00428 session.transaction.xid_state.xid.set(session.getQueryId());
00429
00430 engine->startTransaction(&session, START_TRANS_NO_OPTIONS);
00431
00432
00433 if (! session.getResourceContext(*monitored, 0).isStarted())
00434 registerResourceForStatement(session, monitored, engine, resource_manager);
00435 }
00436
00437 void TransactionServices::allocateNewTransactionId()
00438 {
00439 if (! ReplicationServices::isActive())
00440 {
00441 return;
00442 }
00443
00444 Session *my_session= current_session;
00445 uint64_t xa_id= xa_storage_engine().getNewTransactionId(my_session);
00446 my_session->setXaId(xa_id);
00447 }
00448
00449 uint64_t TransactionServices::getCurrentTransactionId(Session& session)
00450 {
00451 if (session.getXaId() == 0)
00452 {
00453 session.setXaId(xa_storage_engine().getNewTransactionId(&session));
00454 }
00455
00456 return session.getXaId();
00457 }
00458
00459 int TransactionServices::commitTransaction(Session& session,
00460 bool normal_transaction)
00461 {
00462 int error= 0, cookie= 0;
00463
00464
00465
00466
00467 TransactionContext *trans= normal_transaction ? &session.transaction.all : &session.transaction.stmt;
00468 TransactionContext::ResourceContexts &resource_contexts= trans->getResourceContexts();
00469
00470 bool is_real_trans= normal_transaction || session.transaction.all.getResourceContexts().empty();
00471
00472
00473
00474
00475
00476
00477
00478 assert(session.transaction.stmt.getResourceContexts().empty() ||
00479 trans == &session.transaction.stmt);
00480
00481 if (resource_contexts.empty() == false)
00482 {
00483 if (is_real_trans && session.wait_if_global_read_lock(false, false))
00484 {
00485 rollbackTransaction(session, normal_transaction);
00486 return 1;
00487 }
00488
00489
00490
00491
00492
00493
00494 if (shouldConstructMessages())
00495 {
00496 BOOST_FOREACH(TransactionContext::ResourceContexts::reference resource_context, resource_contexts)
00497 {
00498 if (error)
00499 break;
00500
00501
00502
00503
00504
00505 if (! resource_context->hasModifiedData())
00506 continue;
00507
00508 plugin::MonitoredInTransaction *resource= resource_context->getMonitored();
00509
00510 if (resource->participatesInXaTransaction())
00511 {
00512 if (int err= resource_context->getXaResourceManager()->xaPrepare(&session, normal_transaction))
00513 {
00514 my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
00515 error= 1;
00516 }
00517 else
00518 {
00519 session.status_var.ha_prepare_count++;
00520 }
00521 }
00522 }
00523 if (error == 0 && is_real_trans)
00524 {
00525
00526
00527
00528
00529 error= commitTransactionMessage(session);
00530 }
00531 if (error)
00532 {
00533 rollbackTransaction(session, normal_transaction);
00534 error= 1;
00535 goto end;
00536 }
00537 }
00538 error= commitPhaseOne(session, normal_transaction) ? (cookie ? 2 : 1) : 0;
00539 end:
00540 if (is_real_trans)
00541 session.startWaitingGlobalReadLock();
00542 }
00543 return error;
00544 }
00545
00550 int TransactionServices::commitPhaseOne(Session& session,
00551 bool normal_transaction)
00552 {
00553 int error=0;
00554 TransactionContext *trans= normal_transaction ? &session.transaction.all : &session.transaction.stmt;
00555 TransactionContext::ResourceContexts &resource_contexts= trans->getResourceContexts();
00556
00557 bool is_real_trans= normal_transaction || session.transaction.all.getResourceContexts().empty();
00558 bool all= normal_transaction;
00559
00560
00561
00562
00563 if (! session_test_options(&session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
00564 all= true;
00565
00566 if (resource_contexts.empty() == false)
00567 {
00568 BOOST_FOREACH(TransactionContext::ResourceContexts::reference resource_context, resource_contexts)
00569 {
00570 plugin::MonitoredInTransaction *resource= resource_context->getMonitored();
00571
00572 if (resource->participatesInXaTransaction())
00573 {
00574 if (int err= resource_context->getXaResourceManager()->xaCommit(&session, all))
00575 {
00576 my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
00577 error= 1;
00578 }
00579 else if (normal_transaction)
00580 {
00581 session.status_var.ha_commit_count++;
00582 }
00583 }
00584 else if (resource->participatesInSqlTransaction())
00585 {
00586 if (int err= resource_context->getTransactionalStorageEngine()->commit(&session, all))
00587 {
00588 my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
00589 error= 1;
00590 }
00591 else if (normal_transaction)
00592 {
00593 session.status_var.ha_commit_count++;
00594 }
00595 }
00596 resource_context->reset();
00597 }
00598
00599 if (is_real_trans)
00600 session.transaction.xid_state.xid.set_null();
00601
00602 if (normal_transaction)
00603 {
00604 session.variables.tx_isolation= session.session_tx_isolation;
00605 session.transaction.cleanup();
00606 }
00607 }
00608 trans->reset();
00609 return error;
00610 }
00611
00612 int TransactionServices::rollbackTransaction(Session& session,
00613 bool normal_transaction)
00614 {
00615 int error= 0;
00616 TransactionContext *trans= normal_transaction ? &session.transaction.all : &session.transaction.stmt;
00617 TransactionContext::ResourceContexts &resource_contexts= trans->getResourceContexts();
00618
00619 bool is_real_trans= normal_transaction || session.transaction.all.getResourceContexts().empty();
00620 bool all = normal_transaction || !session_test_options(&session, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN);
00621
00622
00623
00624
00625
00626 assert(session.transaction.stmt.getResourceContexts().empty() || trans == &session.transaction.stmt);
00627
00628 if (resource_contexts.empty() == false)
00629 {
00630 BOOST_FOREACH(TransactionContext::ResourceContexts::reference resource_context, resource_contexts)
00631 {
00632 plugin::MonitoredInTransaction *resource= resource_context->getMonitored();
00633
00634 if (resource->participatesInXaTransaction())
00635 {
00636 if (int err= resource_context->getXaResourceManager()->xaRollback(&session, all))
00637 {
00638 my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
00639 error= 1;
00640 }
00641 else if (normal_transaction)
00642 {
00643 session.status_var.ha_rollback_count++;
00644 }
00645 }
00646 else if (resource->participatesInSqlTransaction())
00647 {
00648 if (int err= resource_context->getTransactionalStorageEngine()->rollback(&session, all))
00649 {
00650 my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
00651 error= 1;
00652 }
00653 else if (normal_transaction)
00654 {
00655 session.status_var.ha_rollback_count++;
00656 }
00657 }
00658 resource_context->reset();
00659 }
00660
00661
00662
00663
00664
00665
00666
00667
00668 if (all)
00669 rollbackTransactionMessage(session);
00670 else
00671 rollbackStatementMessage(session);
00672
00673 if (is_real_trans)
00674 session.transaction.xid_state.xid.set_null();
00675 if (normal_transaction)
00676 {
00677 session.variables.tx_isolation=session.session_tx_isolation;
00678 session.transaction.cleanup();
00679 }
00680 }
00681 if (normal_transaction)
00682 session.transaction_rollback_request= false;
00683
00684
00685
00686
00687 if (is_real_trans &&
00688 session.transaction.all.hasModifiedNonTransData() &&
00689 session.getKilled() != Session::KILL_CONNECTION)
00690 {
00691 push_warning(&session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
00692 ER_WARNING_NOT_COMPLETE_ROLLBACK,
00693 ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
00694 }
00695 trans->reset();
00696 return error;
00697 }
00698
00699 int TransactionServices::autocommitOrRollback(Session& session,
00700 int error)
00701 {
00702
00703 message::Statement *statement= session.getStatementMessage();
00704 if ((statement != NULL) && (! error))
00705 finalizeStatementMessage(*statement, session);
00706
00707 if (session.transaction.stmt.getResourceContexts().empty() == false)
00708 {
00709 TransactionContext *trans = &session.transaction.stmt;
00710 TransactionContext::ResourceContexts &resource_contexts= trans->getResourceContexts();
00711 BOOST_FOREACH(TransactionContext::ResourceContexts::reference resource_context, resource_contexts)
00712 {
00713 resource_context->getTransactionalStorageEngine()->endStatement(&session);
00714 }
00715
00716 if (! error)
00717 {
00718 if (commitTransaction(session, false))
00719 error= 1;
00720 }
00721 else
00722 {
00723 (void) rollbackTransaction(session, false);
00724 if (session.transaction_rollback_request)
00725 {
00726 (void) rollbackTransaction(session, true);
00727 session.server_status&= ~SERVER_STATUS_IN_TRANS;
00728 }
00729 }
00730
00731 session.variables.tx_isolation= session.session_tx_isolation;
00732 }
00733
00734 return error;
00735 }
00736
00737 struct ResourceContextCompare : public std::binary_function<ResourceContext *, ResourceContext *, bool>
00738 {
00739 result_type operator()(const ResourceContext *lhs, const ResourceContext *rhs) const
00740 {
00741
00742
00743 return reinterpret_cast<uint64_t>(lhs->getMonitored()) < reinterpret_cast<uint64_t>(rhs->getMonitored());
00744 }
00745 };
00746
00747 int TransactionServices::rollbackToSavepoint(Session& session,
00748 NamedSavepoint &sv)
00749 {
00750 int error= 0;
00751 TransactionContext *trans= &session.transaction.all;
00752 TransactionContext::ResourceContexts &tran_resource_contexts= trans->getResourceContexts();
00753 TransactionContext::ResourceContexts &sv_resource_contexts= sv.getResourceContexts();
00754
00755 trans->no_2pc= false;
00756
00757
00758
00759
00760 BOOST_FOREACH(TransactionContext::ResourceContexts::reference resource_context, sv_resource_contexts)
00761 {
00762 plugin::MonitoredInTransaction *resource= resource_context->getMonitored();
00763
00764 if (resource->participatesInSqlTransaction())
00765 {
00766 if (int err= resource_context->getTransactionalStorageEngine()->rollbackToSavepoint(&session, sv))
00767 {
00768 my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
00769 error= 1;
00770 }
00771 else
00772 {
00773 session.status_var.ha_savepoint_rollback_count++;
00774 }
00775 }
00776 trans->no_2pc|= not resource->participatesInXaTransaction();
00777 }
00778
00779
00780
00781
00782 {
00783 TransactionContext::ResourceContexts sorted_tran_resource_contexts(tran_resource_contexts);
00784 TransactionContext::ResourceContexts sorted_sv_resource_contexts(sv_resource_contexts);
00785 TransactionContext::ResourceContexts set_difference_contexts;
00786
00787
00788
00789
00790
00791
00792 set_difference_contexts.reserve(max(tran_resource_contexts.size(), sv_resource_contexts.size()));
00793
00794 sort(sorted_tran_resource_contexts.begin(),
00795 sorted_tran_resource_contexts.end(),
00796 ResourceContextCompare());
00797 sort(sorted_sv_resource_contexts.begin(),
00798 sorted_sv_resource_contexts.end(),
00799 ResourceContextCompare());
00800 set_difference(sorted_tran_resource_contexts.begin(),
00801 sorted_tran_resource_contexts.end(),
00802 sorted_sv_resource_contexts.begin(),
00803 sorted_sv_resource_contexts.end(),
00804 set_difference_contexts.begin(),
00805 ResourceContextCompare());
00806
00807
00808
00809
00810
00811
00812 BOOST_FOREACH(TransactionContext::ResourceContexts::reference resource_context, set_difference_contexts)
00813 {
00814 plugin::MonitoredInTransaction *resource= resource_context->getMonitored();
00815
00816 if (resource->participatesInSqlTransaction())
00817 {
00818 if (int err= resource_context->getTransactionalStorageEngine()->rollback(&session, true))
00819 {
00820 my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
00821 error= 1;
00822 }
00823 else
00824 {
00825 session.status_var.ha_rollback_count++;
00826 }
00827 }
00828 resource_context->reset();
00829 }
00830 }
00831 trans->setResourceContexts(sv_resource_contexts);
00832
00833 if (shouldConstructMessages())
00834 {
00835 cleanupTransactionMessage(getActiveTransactionMessage(session), session);
00836 message::Transaction *savepoint_transaction= sv.getTransactionMessage();
00837 if (savepoint_transaction != NULL)
00838 {
00839
00840
00841
00842
00843
00844 message::Transaction *savepoint_transaction_copy= new message::Transaction(*sv.getTransactionMessage());
00845 uint32_t num_statements = savepoint_transaction_copy->statement_size();
00846 if (num_statements == 0)
00847 {
00848 session.setStatementMessage(NULL);
00849 }
00850 else
00851 {
00852 session.setStatementMessage(savepoint_transaction_copy->mutable_statement(num_statements - 1));
00853 }
00854 session.setTransactionMessage(savepoint_transaction_copy);
00855 }
00856 }
00857
00858 return error;
00859 }
00860
00867 int TransactionServices::setSavepoint(Session& session,
00868 NamedSavepoint &sv)
00869 {
00870 int error= 0;
00871 TransactionContext *trans= &session.transaction.all;
00872 TransactionContext::ResourceContexts &resource_contexts= trans->getResourceContexts();
00873
00874 if (resource_contexts.empty() == false)
00875 {
00876 BOOST_FOREACH(TransactionContext::ResourceContexts::reference resource_context, resource_contexts)
00877 {
00878 plugin::MonitoredInTransaction *resource= resource_context->getMonitored();
00879
00880 if (resource->participatesInSqlTransaction())
00881 {
00882 if (int err= resource_context->getTransactionalStorageEngine()->setSavepoint(&session, sv))
00883 {
00884 my_error(ER_GET_ERRNO, MYF(0), err);
00885 error= 1;
00886 }
00887 else
00888 {
00889 session.status_var.ha_savepoint_count++;
00890 }
00891 }
00892 }
00893 }
00894
00895
00896
00897 sv.setResourceContexts(resource_contexts);
00898
00899 if (shouldConstructMessages())
00900 {
00901 message::Transaction *transaction= session.getTransactionMessage();
00902
00903 if (transaction != NULL)
00904 {
00905 message::Transaction *transaction_savepoint=
00906 new message::Transaction(*transaction);
00907 sv.setTransactionMessage(transaction_savepoint);
00908 }
00909 }
00910
00911 return error;
00912 }
00913
00914 int TransactionServices::releaseSavepoint(Session& session,
00915 NamedSavepoint &sv)
00916 {
00917 int error= 0;
00918
00919 TransactionContext::ResourceContexts &resource_contexts= sv.getResourceContexts();
00920
00921 BOOST_FOREACH(TransactionContext::ResourceContexts::reference resource_context, resource_contexts)
00922 {
00923 plugin::MonitoredInTransaction *resource= resource_context->getMonitored();
00924
00925 if (resource->participatesInSqlTransaction())
00926 {
00927 if (int err= resource_context->getTransactionalStorageEngine()->releaseSavepoint(&session, sv))
00928 {
00929 my_error(ER_GET_ERRNO, MYF(0), err);
00930 error= 1;
00931 }
00932 }
00933 }
00934
00935 return error;
00936 }
00937
00938 bool TransactionServices::shouldConstructMessages()
00939 {
00940 return ReplicationServices::isActive();
00941 }
00942
00943 message::Transaction *TransactionServices::getActiveTransactionMessage(Session& session,
00944 bool should_inc_trx_id)
00945 {
00946 message::Transaction *transaction= session.getTransactionMessage();
00947
00948 if (unlikely(transaction == NULL))
00949 {
00950
00951
00952
00953
00954
00955 transaction= new message::Transaction();
00956 initTransactionMessage(*transaction, session, should_inc_trx_id);
00957 session.setTransactionMessage(transaction);
00958 }
00959 return transaction;
00960 }
00961
00962 void TransactionServices::initTransactionMessage(message::Transaction &transaction,
00963 Session& session,
00964 bool should_inc_trx_id)
00965 {
00966 message::TransactionContext *trx= transaction.mutable_transaction_context();
00967 trx->set_server_id(session.getServerId());
00968
00969 if (should_inc_trx_id)
00970 {
00971 trx->set_transaction_id(getCurrentTransactionId(session));
00972 session.setXaId(0);
00973 }
00974 else
00975 {
00976
00977 trx->set_transaction_id(0);
00978 }
00979
00980 trx->set_start_timestamp(session.times.getCurrentTimestamp());
00981
00982
00983 transaction.set_segment_id(1);
00984 transaction.set_end_segment(true);
00985 }
00986
00987 void TransactionServices::finalizeTransactionMessage(message::Transaction &transaction,
00988 const Session& session)
00989 {
00990 message::TransactionContext *trx= transaction.mutable_transaction_context();
00991 trx->set_end_timestamp(session.times.getCurrentTimestamp());
00992 }
00993
00994 void TransactionServices::cleanupTransactionMessage(message::Transaction *transaction,
00995 Session& session)
00996 {
00997 delete transaction;
00998 session.setStatementMessage(NULL);
00999 session.setTransactionMessage(NULL);
01000 session.setXaId(0);
01001 }
01002
01003 int TransactionServices::commitTransactionMessage(Session& session)
01004 {
01005 if (! ReplicationServices::isActive())
01006 return 0;
01007
01008
01009
01010
01011
01012 if (session.getTransactionMessage() == NULL)
01013 return 0;
01014
01015
01016 message::Statement *statement= session.getStatementMessage();
01017
01018 if (statement != NULL)
01019 {
01020 finalizeStatementMessage(*statement, session);
01021 }
01022
01023 message::Transaction* transaction= getActiveTransactionMessage(session);
01024
01025
01026
01027
01028
01029
01030
01031 if (transaction->statement_size() == 0)
01032 {
01033 cleanupTransactionMessage(transaction, session);
01034 return 0;
01035 }
01036
01037 finalizeTransactionMessage(*transaction, session);
01038
01039 plugin::ReplicationReturnCode result= ReplicationServices::pushTransactionMessage(session, *transaction);
01040
01041 cleanupTransactionMessage(transaction, session);
01042
01043 return static_cast<int>(result);
01044 }
01045
01046 void TransactionServices::initStatementMessage(message::Statement &statement,
01047 message::Statement::Type type,
01048 const Session& session)
01049 {
01050 statement.set_type(type);
01051 statement.set_start_timestamp(session.times.getCurrentTimestamp());
01052
01053 if (session.variables.replicate_query)
01054 statement.set_sql(session.getQueryString()->c_str());
01055 }
01056
01057 void TransactionServices::finalizeStatementMessage(message::Statement &statement,
01058 Session& session)
01059 {
01060 statement.set_end_timestamp(session.times.getCurrentTimestamp());
01061 session.setStatementMessage(NULL);
01062 }
01063
01064 void TransactionServices::rollbackTransactionMessage(Session& session)
01065 {
01066 if (! ReplicationServices::isActive())
01067 return;
01068
01069 message::Transaction *transaction= getActiveTransactionMessage(session);
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088 if (unlikely(message::transactionContainsBulkSegment(*transaction)))
01089 {
01090
01091 uint64_t trx_id= transaction->transaction_context().transaction_id();
01092 uint32_t seg_id= transaction->segment_id();
01093
01094
01095
01096
01097
01098 transaction->Clear();
01099 initTransactionMessage(*transaction, session, false);
01100
01101
01102 transaction->mutable_transaction_context()->set_transaction_id(trx_id);
01103 transaction->set_segment_id(seg_id);
01104 transaction->set_end_segment(true);
01105
01106 message::Statement *statement= transaction->add_statement();
01107
01108 initStatementMessage(*statement, message::Statement::ROLLBACK, session);
01109 finalizeStatementMessage(*statement, session);
01110
01111 finalizeTransactionMessage(*transaction, session);
01112
01113 (void) ReplicationServices::pushTransactionMessage(session, *transaction);
01114 }
01115
01116 cleanupTransactionMessage(transaction, session);
01117 }
01118
01119 void TransactionServices::rollbackStatementMessage(Session& session)
01120 {
01121 if (! ReplicationServices::isActive())
01122 return;
01123
01124 message::Statement *current_statement= session.getStatementMessage();
01125
01126
01127 if (current_statement == NULL)
01128 return;
01129
01130
01131
01132
01133
01134
01135
01136 bool is_segmented= false;
01137
01138 switch (current_statement->type())
01139 {
01140 case message::Statement::INSERT:
01141 if (current_statement->insert_data().segment_id() > 1)
01142 is_segmented= true;
01143 break;
01144
01145 case message::Statement::UPDATE:
01146 if (current_statement->update_data().segment_id() > 1)
01147 is_segmented= true;
01148 break;
01149
01150 case message::Statement::DELETE:
01151 if (current_statement->delete_data().segment_id() > 1)
01152 is_segmented= true;
01153 break;
01154
01155 default:
01156 break;
01157 }
01158
01159
01160
01161
01162
01163 message::Transaction *transaction= getActiveTransactionMessage(session);
01164 google::protobuf::RepeatedPtrField<message::Statement> *statements_in_txn;
01165 statements_in_txn= transaction->mutable_statement();
01166 statements_in_txn->RemoveLast();
01167 session.setStatementMessage(NULL);
01168
01169
01170
01171
01172
01173
01174 if (is_segmented)
01175 {
01176 current_statement= transaction->add_statement();
01177 initStatementMessage(*current_statement,
01178 message::Statement::ROLLBACK_STATEMENT,
01179 session);
01180 finalizeStatementMessage(*current_statement, session);
01181 }
01182 }
01183
01184 message::Transaction *TransactionServices::segmentTransactionMessage(Session& session,
01185 message::Transaction *transaction)
01186 {
01187 uint64_t trx_id= transaction->transaction_context().transaction_id();
01188 uint32_t seg_id= transaction->segment_id();
01189
01190 transaction->set_end_segment(false);
01191 commitTransactionMessage(session);
01192 transaction= getActiveTransactionMessage(session, false);
01193
01194
01195 transaction->mutable_transaction_context()->set_transaction_id(trx_id);
01196 transaction->set_segment_id(seg_id + 1);
01197 transaction->set_end_segment(true);
01198
01199 return transaction;
01200 }
01201
01202 message::Statement &TransactionServices::getInsertStatement(Session& session,
01203 Table &table,
01204 uint32_t *next_segment_id)
01205 {
01206 message::Statement *statement= session.getStatementMessage();
01207 message::Transaction *transaction= NULL;
01208
01209
01210
01211
01212
01213
01214
01215
01216 if (statement == NULL)
01217 {
01218 transaction= getActiveTransactionMessage(session);
01219
01220 if (static_cast<size_t>(transaction->ByteSize()) >=
01221 transaction_message_threshold)
01222 {
01223 transaction= segmentTransactionMessage(session, transaction);
01224 }
01225
01226 statement= transaction->add_statement();
01227 setInsertHeader(*statement, session, table);
01228 session.setStatementMessage(statement);
01229 }
01230 else
01231 {
01232 transaction= getActiveTransactionMessage(session);
01233
01234
01235
01236
01237
01238
01239 if (static_cast<size_t>(transaction->ByteSize()) >=
01240 transaction_message_threshold)
01241 {
01242
01243 uint64_t trx_id= transaction->transaction_context().transaction_id();
01244 uint32_t seg_id= transaction->segment_id();
01245
01246 message::InsertData *current_data= statement->mutable_insert_data();
01247
01248
01249 *next_segment_id= current_data->segment_id() + 1;
01250
01251 current_data->set_end_segment(false);
01252 transaction->set_end_segment(false);
01253
01254
01255
01256
01257
01258
01259 commitTransactionMessage(session);
01260
01261
01262
01263
01264
01265
01266 transaction= getActiveTransactionMessage(session, false);
01267 assert(transaction != NULL);
01268
01269 statement= transaction->add_statement();
01270 setInsertHeader(*statement, session, table);
01271 session.setStatementMessage(statement);
01272
01273
01274 transaction->mutable_transaction_context()->set_transaction_id(trx_id);
01275 transaction->set_segment_id(seg_id + 1);
01276 transaction->set_end_segment(true);
01277 }
01278 else
01279 {
01280
01281
01282
01283
01284 const message::InsertData ¤t_data= statement->insert_data();
01285 *next_segment_id= current_data.segment_id();
01286 }
01287 }
01288
01289 return *statement;
01290 }
01291
01292 void TransactionServices::setInsertHeader(message::Statement &statement,
01293 const Session& session,
01294 Table &table)
01295 {
01296 initStatementMessage(statement, message::Statement::INSERT, session);
01297
01298
01299
01300
01301
01302
01303 message::InsertHeader *header= statement.mutable_insert_header();
01304 message::TableMetadata *table_metadata= header->mutable_table_metadata();
01305
01306 table_metadata->set_schema_name(table.getShare()->getSchemaName());
01307 table_metadata->set_table_name(table.getShare()->getTableName());
01308
01309 Field **table_fields= table.getFields();
01310
01311 message::FieldMetadata *field_metadata;
01312
01313
01314 table.setReadSet();
01315
01316 while (Field* current_field= *table_fields++)
01317 {
01318 field_metadata= header->add_field_metadata();
01319 field_metadata->set_name(current_field->field_name);
01320 field_metadata->set_type(message::internalFieldTypeToFieldProtoType(current_field->type()));
01321 }
01322 }
01323
01324 bool TransactionServices::insertRecord(Session& session,
01325 Table &table)
01326 {
01327 if (! ReplicationServices::isActive())
01328 return false;
01329
01330 if (not table.getShare()->is_replicated())
01331 return false;
01332
01341 if (not table.getShare()->hasPrimaryKey())
01342 {
01343 my_error(ER_NO_PRIMARY_KEY_ON_REPLICATED_TABLE, MYF(0));
01344 return true;
01345 }
01346
01347 uint32_t next_segment_id= 1;
01348 message::Statement &statement= getInsertStatement(session, table, &next_segment_id);
01349
01350 message::InsertData *data= statement.mutable_insert_data();
01351 data->set_segment_id(next_segment_id);
01352 data->set_end_segment(true);
01353 message::InsertRecord *record= data->add_record();
01354
01355 Field *current_field;
01356 Field **table_fields= table.getFields();
01357
01358 String *string_value= new (session.mem_root) String(TransactionServices::DEFAULT_RECORD_SIZE);
01359 string_value->set_charset(system_charset_info);
01360
01361
01362 table.setReadSet();
01363
01364 while ((current_field= *table_fields++) != NULL)
01365 {
01366 if (current_field->is_null())
01367 {
01368 record->add_is_null(true);
01369 record->add_insert_value("", 0);
01370 }
01371 else
01372 {
01373 string_value= current_field->val_str_internal(string_value);
01374 record->add_is_null(false);
01375 record->add_insert_value(string_value->c_ptr(), string_value->length());
01376 string_value->free();
01377 }
01378 }
01379 return false;
01380 }
01381
01382 message::Statement &TransactionServices::getUpdateStatement(Session& session,
01383 Table &table,
01384 const unsigned char *old_record,
01385 const unsigned char *new_record,
01386 uint32_t *next_segment_id)
01387 {
01388 message::Statement *statement= session.getStatementMessage();
01389 message::Transaction *transaction= NULL;
01390
01391
01392
01393
01394
01395
01396
01397
01398 if (statement == NULL)
01399 {
01400 transaction= getActiveTransactionMessage(session);
01401
01402 if (static_cast<size_t>(transaction->ByteSize()) >=
01403 transaction_message_threshold)
01404 {
01405 transaction= segmentTransactionMessage(session, transaction);
01406 }
01407
01408 statement= transaction->add_statement();
01409 setUpdateHeader(*statement, session, table, old_record, new_record);
01410 session.setStatementMessage(statement);
01411 }
01412 else
01413 {
01414 transaction= getActiveTransactionMessage(session);
01415
01416
01417
01418
01419
01420
01421 if (static_cast<size_t>(transaction->ByteSize()) >=
01422 transaction_message_threshold)
01423 {
01424
01425 uint64_t trx_id= transaction->transaction_context().transaction_id();
01426 uint32_t seg_id= transaction->segment_id();
01427
01428 message::UpdateData *current_data= statement->mutable_update_data();
01429
01430
01431 *next_segment_id= current_data->segment_id() + 1;
01432
01433 current_data->set_end_segment(false);
01434 transaction->set_end_segment(false);
01435
01436
01437
01438
01439
01440
01441 commitTransactionMessage(session);
01442
01443
01444
01445
01446
01447
01448 transaction= getActiveTransactionMessage(session, false);
01449 assert(transaction != NULL);
01450
01451 statement= transaction->add_statement();
01452 setUpdateHeader(*statement, session, table, old_record, new_record);
01453 session.setStatementMessage(statement);
01454
01455
01456 transaction->mutable_transaction_context()->set_transaction_id(trx_id);
01457 transaction->set_segment_id(seg_id + 1);
01458 transaction->set_end_segment(true);
01459 }
01460 else
01461 {
01462
01463
01464
01465
01466 const message::UpdateData ¤t_data= statement->update_data();
01467 *next_segment_id= current_data.segment_id();
01468 }
01469 }
01470
01471 return *statement;
01472 }
01473
01474 void TransactionServices::setUpdateHeader(message::Statement &statement,
01475 const Session& session,
01476 Table &table,
01477 const unsigned char *old_record,
01478 const unsigned char *new_record)
01479 {
01480 initStatementMessage(statement, message::Statement::UPDATE, session);
01481
01482
01483
01484
01485
01486
01487 message::UpdateHeader *header= statement.mutable_update_header();
01488 message::TableMetadata *table_metadata= header->mutable_table_metadata();
01489
01490 table_metadata->set_schema_name(table.getShare()->getSchemaName());
01491 table_metadata->set_table_name(table.getShare()->getTableName());
01492
01493 Field *current_field;
01494 Field **table_fields= table.getFields();
01495
01496 message::FieldMetadata *field_metadata;
01497
01498
01499 table.setReadSet();
01500
01501 while ((current_field= *table_fields++) != NULL)
01502 {
01503
01504
01505
01506
01507 if (table.getShare()->fieldInPrimaryKey(current_field))
01508 {
01509 field_metadata= header->add_key_field_metadata();
01510 field_metadata->set_name(current_field->field_name);
01511 field_metadata->set_type(message::internalFieldTypeToFieldProtoType(current_field->type()));
01512 }
01513
01514 if (isFieldUpdated(current_field, table, old_record, new_record))
01515 {
01516
01517 field_metadata= header->add_set_field_metadata();
01518 field_metadata->set_name(current_field->field_name);
01519 field_metadata->set_type(message::internalFieldTypeToFieldProtoType(current_field->type()));
01520 }
01521 }
01522 }
01523
01524 void TransactionServices::updateRecord(Session& session,
01525 Table &table,
01526 const unsigned char *old_record,
01527 const unsigned char *new_record)
01528 {
01529 if (! ReplicationServices::isActive())
01530 return;
01531
01532 if (not table.getShare()->is_replicated())
01533 return;
01534
01535 uint32_t next_segment_id= 1;
01536 message::Statement &statement= getUpdateStatement(session, table, old_record, new_record, &next_segment_id);
01537
01538 message::UpdateData *data= statement.mutable_update_data();
01539 data->set_segment_id(next_segment_id);
01540 data->set_end_segment(true);
01541 message::UpdateRecord *record= data->add_record();
01542
01543 Field *current_field;
01544 Field **table_fields= table.getFields();
01545 String *string_value= new (session.mem_root) String(TransactionServices::DEFAULT_RECORD_SIZE);
01546 string_value->set_charset(system_charset_info);
01547
01548 while ((current_field= *table_fields++) != NULL)
01549 {
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561 if (isFieldUpdated(current_field, table, old_record, new_record))
01562 {
01563
01564 bool is_read_set= current_field->isReadSet();
01565
01566
01567 table.setReadSet(current_field->position());
01568
01569
01570 string_value= current_field->val_str_internal(string_value);
01571
01572
01573
01574
01575
01576 current_field->setReadSet(is_read_set);
01577
01578 if (current_field->is_null())
01579 {
01580 record->add_is_null(true);
01581 record->add_after_value("", 0);
01582 }
01583 else
01584 {
01585 record->add_is_null(false);
01586 record->add_after_value(string_value->c_ptr(), string_value->length());
01587 }
01588 string_value->free();
01589 }
01590
01591
01592
01593
01594
01595
01596 if (table.getShare()->fieldInPrimaryKey(current_field))
01597 {
01603 string_value= current_field->val_str_internal(string_value,
01604 old_record +
01605 current_field->offset(const_cast<unsigned char *>(new_record)));
01606 record->add_key_value(string_value->c_ptr(), string_value->length());
01607 string_value->free();
01608 }
01609
01610 }
01611 }
01612
01613 bool TransactionServices::isFieldUpdated(Field *current_field,
01614 Table &table,
01615 const unsigned char *old_record,
01616 const unsigned char *new_record)
01617 {
01618
01619
01620
01621
01622
01623 const unsigned char *old_ptr= (const unsigned char *) old_record + (ptrdiff_t) (current_field->ptr - table.getInsertRecord());
01624 const unsigned char *new_ptr= (const unsigned char *) new_record + (ptrdiff_t) (current_field->ptr - table.getInsertRecord());
01625
01626 uint32_t field_length= current_field->pack_length();
01628 bool old_value_is_null= current_field->is_null_in_record(old_record);
01629 bool new_value_is_null= current_field->is_null_in_record(new_record);
01630
01631 bool isUpdated= false;
01632 if (old_value_is_null != new_value_is_null)
01633 {
01634 if ((old_value_is_null) && (! new_value_is_null))
01635 {
01636 isUpdated= true;
01637 }
01638 else if ((! old_value_is_null) && (new_value_is_null))
01639 {
01640 isUpdated= true;
01641 }
01642 }
01643
01644 if (! isUpdated)
01645 {
01646 if (memcmp(old_ptr, new_ptr, field_length) != 0)
01647 {
01648 isUpdated= true;
01649 }
01650 }
01651 return isUpdated;
01652 }
01653
01654 message::Statement &TransactionServices::getDeleteStatement(Session& session,
01655 Table &table,
01656 uint32_t *next_segment_id)
01657 {
01658 message::Statement *statement= session.getStatementMessage();
01659 message::Transaction *transaction= NULL;
01660
01661
01662
01663
01664
01665
01666
01667
01668 if (statement == NULL)
01669 {
01670 transaction= getActiveTransactionMessage(session);
01671
01672 if (static_cast<size_t>(transaction->ByteSize()) >=
01673 transaction_message_threshold)
01674 {
01675 transaction= segmentTransactionMessage(session, transaction);
01676 }
01677
01678 statement= transaction->add_statement();
01679 setDeleteHeader(*statement, session, table);
01680 session.setStatementMessage(statement);
01681 }
01682 else
01683 {
01684 transaction= getActiveTransactionMessage(session);
01685
01686
01687
01688
01689
01690
01691 if (static_cast<size_t>(transaction->ByteSize()) >=
01692 transaction_message_threshold)
01693 {
01694
01695 uint64_t trx_id= transaction->transaction_context().transaction_id();
01696 uint32_t seg_id= transaction->segment_id();
01697
01698 message::DeleteData *current_data= statement->mutable_delete_data();
01699
01700
01701 *next_segment_id= current_data->segment_id() + 1;
01702
01703 current_data->set_end_segment(false);
01704 transaction->set_end_segment(false);
01705
01706
01707
01708
01709
01710
01711 commitTransactionMessage(session);
01712
01713
01714
01715
01716
01717
01718 transaction= getActiveTransactionMessage(session, false);
01719 assert(transaction != NULL);
01720
01721 statement= transaction->add_statement();
01722 setDeleteHeader(*statement, session, table);
01723 session.setStatementMessage(statement);
01724
01725
01726 transaction->mutable_transaction_context()->set_transaction_id(trx_id);
01727 transaction->set_segment_id(seg_id + 1);
01728 transaction->set_end_segment(true);
01729 }
01730 else
01731 {
01732
01733
01734
01735
01736 const message::DeleteData ¤t_data= statement->delete_data();
01737 *next_segment_id= current_data.segment_id();
01738 }
01739 }
01740
01741 return *statement;
01742 }
01743
01744 void TransactionServices::setDeleteHeader(message::Statement &statement,
01745 const Session& session,
01746 Table &table)
01747 {
01748 initStatementMessage(statement, message::Statement::DELETE, session);
01749
01750
01751
01752
01753
01754 message::DeleteHeader *header= statement.mutable_delete_header();
01755 message::TableMetadata *table_metadata= header->mutable_table_metadata();
01756
01757 table_metadata->set_schema_name(table.getShare()->getSchemaName());
01758 table_metadata->set_table_name(table.getShare()->getTableName());
01759
01760 Field *current_field;
01761 Field **table_fields= table.getFields();
01762
01763 message::FieldMetadata *field_metadata;
01764
01765 while ((current_field= *table_fields++) != NULL)
01766 {
01767
01768
01769
01770
01771
01772 if (table.getShare()->fieldInPrimaryKey(current_field))
01773 {
01774 field_metadata= header->add_key_field_metadata();
01775 field_metadata->set_name(current_field->field_name);
01776 field_metadata->set_type(message::internalFieldTypeToFieldProtoType(current_field->type()));
01777 }
01778 }
01779 }
01780
01781 void TransactionServices::deleteRecord(Session& session,
01782 Table &table,
01783 bool use_update_record)
01784 {
01785 if (! ReplicationServices::isActive())
01786 return;
01787
01788 if (not table.getShare()->is_replicated())
01789 return;
01790
01791 uint32_t next_segment_id= 1;
01792 message::Statement &statement= getDeleteStatement(session, table, &next_segment_id);
01793
01794 message::DeleteData *data= statement.mutable_delete_data();
01795 data->set_segment_id(next_segment_id);
01796 data->set_end_segment(true);
01797 message::DeleteRecord *record= data->add_record();
01798
01799 Field *current_field;
01800 Field **table_fields= table.getFields();
01801 String *string_value= new (session.mem_root) String(TransactionServices::DEFAULT_RECORD_SIZE);
01802 string_value->set_charset(system_charset_info);
01803
01804 while ((current_field= *table_fields++) != NULL)
01805 {
01806
01807
01808
01809
01810
01811 if (table.getShare()->fieldInPrimaryKey(current_field))
01812 {
01813 if (use_update_record)
01814 {
01815
01816
01817
01818
01819
01820
01821
01822 const unsigned char *old_ptr= current_field->ptr;
01823 current_field->ptr= table.getUpdateRecord() + static_cast<ptrdiff_t>(old_ptr - table.getInsertRecord());
01824 string_value= current_field->val_str_internal(string_value);
01825 current_field->ptr= const_cast<unsigned char *>(old_ptr);
01826 }
01827 else
01828 {
01829 string_value= current_field->val_str_internal(string_value);
01833 }
01834 record->add_key_value(string_value->c_ptr(), string_value->length());
01835 string_value->free();
01836 }
01837 }
01838 }
01839
01840 void TransactionServices::createTable(Session& session,
01841 const message::Table &table)
01842 {
01843 if (not ReplicationServices::isActive())
01844 return;
01845
01846 if (not message::is_replicated(table))
01847 return;
01848
01849 message::Transaction *transaction= getActiveTransactionMessage(session);
01850 message::Statement *statement= transaction->add_statement();
01851
01852 initStatementMessage(*statement, message::Statement::CREATE_TABLE, session);
01853
01854
01855
01856
01857
01858 message::CreateTableStatement *create_table_statement= statement->mutable_create_table_statement();
01859 message::Table *new_table_message= create_table_statement->mutable_table();
01860 *new_table_message= table;
01861
01862 finalizeStatementMessage(*statement, session);
01863
01864 finalizeTransactionMessage(*transaction, session);
01865
01866 (void) ReplicationServices::pushTransactionMessage(session, *transaction);
01867
01868 cleanupTransactionMessage(transaction, session);
01869
01870 }
01871
01872 void TransactionServices::createSchema(Session& session,
01873 const message::Schema &schema)
01874 {
01875 if (! ReplicationServices::isActive())
01876 return;
01877
01878 if (not message::is_replicated(schema))
01879 return;
01880
01881 message::Transaction *transaction= getActiveTransactionMessage(session);
01882 message::Statement *statement= transaction->add_statement();
01883
01884 initStatementMessage(*statement, message::Statement::CREATE_SCHEMA, session);
01885
01886
01887
01888
01889
01890 message::CreateSchemaStatement *create_schema_statement= statement->mutable_create_schema_statement();
01891 message::Schema *new_schema_message= create_schema_statement->mutable_schema();
01892 *new_schema_message= schema;
01893
01894 finalizeStatementMessage(*statement, session);
01895
01896 finalizeTransactionMessage(*transaction, session);
01897
01898 (void) ReplicationServices::pushTransactionMessage(session, *transaction);
01899
01900 cleanupTransactionMessage(transaction, session);
01901
01902 }
01903
01904 void TransactionServices::dropSchema(Session& session,
01905 const identifier::Schema& identifier,
01906 message::schema::const_reference schema)
01907 {
01908 if (not ReplicationServices::isActive())
01909 return;
01910
01911 if (not message::is_replicated(schema))
01912 return;
01913
01914 message::Transaction *transaction= getActiveTransactionMessage(session);
01915 message::Statement *statement= transaction->add_statement();
01916
01917 initStatementMessage(*statement, message::Statement::DROP_SCHEMA, session);
01918
01919
01920
01921
01922
01923 message::DropSchemaStatement *drop_schema_statement= statement->mutable_drop_schema_statement();
01924
01925 drop_schema_statement->set_schema_name(identifier.getSchemaName());
01926
01927 finalizeStatementMessage(*statement, session);
01928
01929 finalizeTransactionMessage(*transaction, session);
01930
01931 (void) ReplicationServices::pushTransactionMessage(session, *transaction);
01932
01933 cleanupTransactionMessage(transaction, session);
01934 }
01935
01936 void TransactionServices::alterSchema(Session& session,
01937 const message::Schema &old_schema,
01938 const message::Schema &new_schema)
01939 {
01940 if (! ReplicationServices::isActive())
01941 return;
01942
01943 if (not message::is_replicated(old_schema))
01944 return;
01945
01946 message::Transaction *transaction= getActiveTransactionMessage(session);
01947 message::Statement *statement= transaction->add_statement();
01948
01949 initStatementMessage(*statement, message::Statement::ALTER_SCHEMA, session);
01950
01951
01952
01953
01954
01955 message::AlterSchemaStatement *alter_schema_statement= statement->mutable_alter_schema_statement();
01956
01957 message::Schema *before= alter_schema_statement->mutable_before();
01958 message::Schema *after= alter_schema_statement->mutable_after();
01959
01960 *before= old_schema;
01961 *after= new_schema;
01962
01963 finalizeStatementMessage(*statement, session);
01964
01965 finalizeTransactionMessage(*transaction, session);
01966
01967 (void) ReplicationServices::pushTransactionMessage(session, *transaction);
01968
01969 cleanupTransactionMessage(transaction, session);
01970 }
01971
01972 void TransactionServices::dropTable(Session& session,
01973 const identifier::Table& identifier,
01974 message::table::const_reference table,
01975 bool if_exists)
01976 {
01977 if (! ReplicationServices::isActive())
01978 return;
01979
01980 if (not message::is_replicated(table))
01981 return;
01982
01983 message::Transaction *transaction= getActiveTransactionMessage(session);
01984 message::Statement *statement= transaction->add_statement();
01985
01986 initStatementMessage(*statement, message::Statement::DROP_TABLE, session);
01987
01988
01989
01990
01991
01992 message::DropTableStatement *drop_table_statement= statement->mutable_drop_table_statement();
01993
01994 drop_table_statement->set_if_exists_clause(if_exists);
01995
01996 message::TableMetadata *table_metadata= drop_table_statement->mutable_table_metadata();
01997
01998 table_metadata->set_schema_name(identifier.getSchemaName());
01999 table_metadata->set_table_name(identifier.getTableName());
02000
02001 finalizeStatementMessage(*statement, session);
02002
02003 finalizeTransactionMessage(*transaction, session);
02004
02005 (void) ReplicationServices::pushTransactionMessage(session, *transaction);
02006
02007 cleanupTransactionMessage(transaction, session);
02008 }
02009
02010 void TransactionServices::truncateTable(Session& session, Table &table)
02011 {
02012 if (! ReplicationServices::isActive())
02013 return;
02014
02015 if (not table.getShare()->is_replicated())
02016 return;
02017
02018 message::Transaction *transaction= getActiveTransactionMessage(session);
02019 message::Statement *statement= transaction->add_statement();
02020
02021 initStatementMessage(*statement, message::Statement::TRUNCATE_TABLE, session);
02022
02023
02024
02025
02026
02027 message::TruncateTableStatement *truncate_statement= statement->mutable_truncate_table_statement();
02028 message::TableMetadata *table_metadata= truncate_statement->mutable_table_metadata();
02029
02030 table_metadata->set_schema_name(table.getShare()->getSchemaName());
02031 table_metadata->set_table_name(table.getShare()->getTableName());
02032
02033 finalizeStatementMessage(*statement, session);
02034
02035 finalizeTransactionMessage(*transaction, session);
02036
02037 (void) ReplicationServices::pushTransactionMessage(session, *transaction);
02038
02039 cleanupTransactionMessage(transaction, session);
02040 }
02041
02042 void TransactionServices::rawStatement(Session& session,
02043 const string &query,
02044 const string &schema)
02045 {
02046 if (! ReplicationServices::isActive())
02047 return;
02048
02049 message::Transaction *transaction= getActiveTransactionMessage(session);
02050 message::Statement *statement= transaction->add_statement();
02051
02052 initStatementMessage(*statement, message::Statement::RAW_SQL, session);
02053 statement->set_sql(query);
02054 if (not schema.empty())
02055 statement->set_raw_sql_schema(schema);
02056 finalizeStatementMessage(*statement, session);
02057
02058 finalizeTransactionMessage(*transaction, session);
02059
02060 (void) ReplicationServices::pushTransactionMessage(session, *transaction);
02061
02062 cleanupTransactionMessage(transaction, session);
02063 }
02064
02065 int TransactionServices::sendEvent(Session& session, const message::Event &event)
02066 {
02067 if (not ReplicationServices::isActive())
02068 return 0;
02069 message::Transaction transaction;
02070
02071
02072 initTransactionMessage(transaction, session, true);
02073
02074
02075 finalizeTransactionMessage(transaction, session);
02076
02077 message::Event *trx_event= transaction.mutable_event();
02078 trx_event->CopyFrom(event);
02079 plugin::ReplicationReturnCode result= ReplicationServices::pushTransactionMessage(session, transaction);
02080 return result;
02081 }
02082
02083 bool TransactionServices::sendStartupEvent(Session& session)
02084 {
02085 message::Event event;
02086 event.set_type(message::Event::STARTUP);
02087 return not sendEvent(session, event);
02088 }
02089
02090 bool TransactionServices::sendShutdownEvent(Session& session)
02091 {
02092 message::Event event;
02093 event.set_type(message::Event::SHUTDOWN);
02094 return not sendEvent(session, event);
02095 }
02096
02097 }