From: Li-Bing.Song Date: January 31 2010 1:41pm Subject: bzr commit into mysql-5.5-next-mr branch (Li-Bing.Song:2979) Bug#50157 List-Archive: http://lists.mysql.com/commits/98778 X-Bug: 50157 Message-Id: <201001311343.o0VDh46O012083@anders-server> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============5720571594975708533==" --===============5720571594975708533== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/anders/work/bzrroot/mysql-next-mr-bugfixing/ based on revid:aelkin@stripped 2979 Li-Bing.Song@stripped 2010-01-31 [merge] Manual Merge for bug#50157 modified: mysql-test/suite/rpl/r/rpl_semi_sync.result mysql-test/suite/rpl/t/rpl_semi_sync.test plugin/semisync/semisync_master.cc plugin/semisync/semisync_master.h sql/rpl_handler.cc === modified file 'mysql-test/suite/rpl/r/rpl_semi_sync.result' --- a/mysql-test/suite/rpl/r/rpl_semi_sync.result 2009-10-23 04:56:30 +0000 +++ b/mysql-test/suite/rpl/r/rpl_semi_sync.result 2010-01-30 18:26:51 +0000 @@ -120,8 +120,27 @@ min(a) select max(a) from t1; max(a) 300 + +# BUG#50157 +# semi-sync replication crashes when replicating a transaction which +# include 'CREATE TEMPORARY TABLE `MyISAM_t` SELECT * FROM `Innodb_t` ; +[ on master ] +SET SESSION AUTOCOMMIT= 0; +CREATE TABLE t2(c1 INT) ENGINE=innodb; +BEGIN; + +# Even though it is in a transaction, this statement is binlogged into binlog +# file immediately. +CREATE TEMPORARY TABLE t3 SELECT c1 FROM t2 where 1=1; + +# These statements will not be binlogged until the transaction is committed +INSERT INTO t2 VALUES(11); +INSERT INTO t2 VALUES(22); +COMMIT; +DROP TABLE t2, t3; +SET SESSION AUTOCOMMIT= 1; # -# Test semi-sync master will switch OFF after one transacton +# Test semi-sync master will switch OFF after one transaction # timeout waiting for slave reply. # include/stop_slave.inc @@ -135,7 +154,7 @@ Variable_name Value Rpl_semi_sync_master_no_tx 0 show status like 'Rpl_semi_sync_master_yes_tx'; Variable_name Value -Rpl_semi_sync_master_yes_tx 301 +Rpl_semi_sync_master_yes_tx 304 show status like 'Rpl_semi_sync_master_clients'; Variable_name Value Rpl_semi_sync_master_clients 1 @@ -150,7 +169,7 @@ Variable_name Value Rpl_semi_sync_master_no_tx 1 show status like 'Rpl_semi_sync_master_yes_tx'; Variable_name Value -Rpl_semi_sync_master_yes_tx 301 +Rpl_semi_sync_master_yes_tx 304 insert into t1 values (100); [ master status should be OFF ] show status like 'Rpl_semi_sync_master_status'; @@ -161,7 +180,7 @@ Variable_name Value Rpl_semi_sync_master_no_tx 302 show status like 'Rpl_semi_sync_master_yes_tx'; Variable_name Value -Rpl_semi_sync_master_yes_tx 301 +Rpl_semi_sync_master_yes_tx 304 # # Test semi-sync status on master will be ON again when slave catches up # @@ -194,7 +213,7 @@ Variable_name Value Rpl_semi_sync_master_no_tx 302 show status like 'Rpl_semi_sync_master_yes_tx'; Variable_name Value -Rpl_semi_sync_master_yes_tx 301 +Rpl_semi_sync_master_yes_tx 304 show status like 'Rpl_semi_sync_master_clients'; Variable_name Value Rpl_semi_sync_master_clients 1 @@ -213,7 +232,7 @@ Variable_name Value Rpl_semi_sync_master_no_tx 302 SHOW STATUS LIKE 'Rpl_semi_sync_master_yes_tx'; Variable_name Value -Rpl_semi_sync_master_yes_tx 302 +Rpl_semi_sync_master_yes_tx 305 FLUSH NO_WRITE_TO_BINLOG STATUS; [ Semi-sync master status variables after FLUSH STATUS ] SHOW STATUS LIKE 'Rpl_semi_sync_master_no_tx'; === modified file 'mysql-test/suite/rpl/t/rpl_semi_sync.test' --- a/mysql-test/suite/rpl/t/rpl_semi_sync.test 2009-10-23 04:56:30 +0000 +++ b/mysql-test/suite/rpl/t/rpl_semi_sync.test 2010-01-30 18:26:51 +0000 @@ -11,6 +11,7 @@ disable_query_log; connection master; call mtr.add_suppression("Timeout waiting for reply of binlog"); call mtr.add_suppression("Read semi-sync reply"); +call mtr.add_suppression("Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT."); connection slave; call mtr.add_suppression("Master server does not support semi-sync"); call mtr.add_suppression("Semi-sync slave .* reply"); @@ -193,8 +194,38 @@ select count(distinct a) from t1; select min(a) from t1; select max(a) from t1; +--echo +--echo # BUG#50157 +--echo # semi-sync replication crashes when replicating a transaction which +--echo # include 'CREATE TEMPORARY TABLE `MyISAM_t` SELECT * FROM `Innodb_t` ; + +connection master; +echo [ on master ]; +SET SESSION AUTOCOMMIT= 0; +CREATE TABLE t2(c1 INT) ENGINE=innodb; +sync_slave_with_master; + +connection master; +BEGIN; +--echo +--echo # Even though it is in a transaction, this statement is binlogged into binlog +--echo # file immediately. +--disable_warnings +CREATE TEMPORARY TABLE t3 SELECT c1 FROM t2 where 1=1; +--enable_warnings +--echo +--echo # These statements will not be binlogged until the transaction is committed +INSERT INTO t2 VALUES(11); +INSERT INTO t2 VALUES(22); +COMMIT; + +DROP TABLE t2, t3; +SET SESSION AUTOCOMMIT= 1; +sync_slave_with_master; + + --echo # ---echo # Test semi-sync master will switch OFF after one transacton +--echo # Test semi-sync master will switch OFF after one transaction --echo # timeout waiting for slave reply. --echo # connection slave; === modified file 'plugin/semisync/semisync_master.cc' --- a/plugin/semisync/semisync_master.cc 2009-12-11 08:58:13 +0000 +++ b/plugin/semisync/semisync_master.cc 2010-01-31 13:37:41 +0000 @@ -65,7 +65,7 @@ static int gettimeofday(struct timeval * ActiveTranx::ActiveTranx(mysql_mutex_t *lock, unsigned long trace_level) - : Trace(trace_level), + : Trace(trace_level), allocator_(max_connections), num_entries_(max_connections << 1), /* Transaction hash table size * is set to double the size * of max_connections */ @@ -115,25 +115,6 @@ unsigned int ActiveTranx::get_hash_value return (hash1 + hash2) % num_entries_; } -ActiveTranx::TranxNode* ActiveTranx::alloc_tranx_node() -{ - MYSQL_THD thd= (MYSQL_THD)current_thd; - /* The memory allocated for TranxNode will be automatically freed at - the end of the command of current THD. And because - ha_autocommit_or_rollback() will always be called before that, so - we are sure that the node will be removed from the active list - before it get freed. */ - TranxNode *trx_node = (TranxNode *)thd_alloc(thd, sizeof(TranxNode)); - if (trx_node) - { - trx_node->log_name_[0] = '\0'; - trx_node->log_pos_= 0; - trx_node->next_= 0; - trx_node->hash_next_= 0; - } - return trx_node; -} - int ActiveTranx::compare(const char *log_file_name1, my_off_t log_file_pos1, const char *log_file_name2, my_off_t log_file_pos2) { @@ -159,7 +140,7 @@ int ActiveTranx::insert_tranx_node(const function_enter(kWho); - ins_node = alloc_tranx_node(); + ins_node = allocator_.allocate_node(); if (!ins_node) { sql_print_error("%s: transaction node allocation failed for: (%s, %lu)", @@ -271,6 +252,7 @@ int ActiveTranx::clear_active_tranx_node /* Clear the hash table. */ memset(trx_htb_, 0, num_entries_ * sizeof(TranxNode *)); + allocator_.free_all_nodes(); /* Clear the active transaction list. */ if (trx_front_ != NULL) @@ -311,6 +293,7 @@ int ActiveTranx::clear_active_tranx_node } trx_front_ = new_front; + allocator_.free_nodes_before(trx_front_); if (trace_level_ & kTraceDetail) sql_print_information("%s: cleared %d nodes back until pos (%s, %lu)", === modified file 'plugin/semisync/semisync_master.h' --- a/plugin/semisync/semisync_master.h 2009-12-11 08:58:13 +0000 +++ b/plugin/semisync/semisync_master.h 2010-01-31 13:37:41 +0000 @@ -26,6 +26,266 @@ extern PSI_mutex_key key_ss_mutex_LOCK_b extern PSI_cond_key key_ss_cond_COND_binlog_send_; #endif +struct TranxNode { + char log_name_[FN_REFLEN]; + my_off_t log_pos_; + struct TranxNode *next_; /* the next node in the sorted list */ + struct TranxNode *hash_next_; /* the next node during hash collision */ +}; + +/** + @class TranxNodeAllocator + + This class provides memory allocating and freeing methods for + TranxNode. The main target is performance. + + @section ALLOCATE How to allocate a node + The pointer of the first node after 'last_node' in current_block is + returned. current_block will move to the next free Block when all nodes of + it are in use. A new Block is allocated and is put into the rear of the + Block link table if no Block is free. + + The list starts up empty (ie, there is no allocated Block). + + After some nodes are freed, there probably are some free nodes before + the sequence of the allocated nodes, but we do not reuse it. It is better + to keep the allocated nodes are in the sequence, for it is more efficient + for allocating and freeing TranxNode. + + @section FREENODE How to free nodes + There are two methods for freeing nodes. They are free_all_nodes and + free_nodes_before. + + 'A Block is free' means all of its nodes are free. + @subsection free_nodes_before + As all allocated nodes are in the sequence, 'Before one node' means all + nodes before given node in the same Block and all Blocks before the Block + which containing the given node. As such, all Blocks before the given one + ('node') are free Block and moved into the rear of the Block link table. + The Block containing the given 'node', however, is not. For at least the + given 'node' is still in use. This will waste at most one Block, but it is + more efficient. + */ +#define BLOCK_TRANX_NODES 16 +class TranxNodeAllocator +{ +public: + /** + @param reserved_nodes + The number of reserved TranxNodes. It is used to set 'reserved_blocks' + which can contain at least 'reserved_nodes' number of TranxNodes. When + freeing memory, we will reserve at least reserved_blocks of Blocks not + freed. + */ + TranxNodeAllocator(uint reserved_nodes) : + reserved_blocks(reserved_nodes/BLOCK_TRANX_NODES + + (reserved_nodes%BLOCK_TRANX_NODES > 1 ? 2 : 1)), + first_block(NULL), last_block(NULL), + current_block(NULL), last_node(-1), block_num(0) {} + + ~TranxNodeAllocator() + { + Block *block= first_block; + while (block != NULL) + { + Block *next= block->next; + free_block(block); + block= next; + } + } + + /** + The pointer of the first node after 'last_node' in current_block is + returned. current_block will move to the next free Block when all nodes of + it are in use. A new Block is allocated and is put into the rear of the + Block link table if no Block is free. + + @return Return a TranxNode *, or NULL if an error occured. + */ + TranxNode *allocate_node() + { + TranxNode *trx_node; + Block *block= current_block; + + if (last_node == BLOCK_TRANX_NODES-1) + { + current_block= current_block->next; + last_node= -1; + } + + if (current_block == NULL && allocate_block()) + { + current_block= block; + if (current_block) + last_node= BLOCK_TRANX_NODES-1; + return NULL; + } + + trx_node= &(current_block->nodes[++last_node]); + trx_node->log_name_[0] = '\0'; + trx_node->log_pos_= 0; + trx_node->next_= 0; + trx_node->hash_next_= 0; + return trx_node; + } + + /** + All nodes are freed. + + @return Return 0, or 1 if an error occured. + */ + int free_all_nodes() + { + current_block= first_block; + last_node= -1; + free_blocks(); + return 0; + } + + /** + All Blocks before the given 'node' are free Block and moved into the rear + of the Block link table. + + @param node All nodes before 'node' will be freed + + @return Return 0, or 1 if an error occured. + */ + int free_nodes_before(TranxNode* node) + { + Block *block; + Block *prev_block; + + block= first_block; + while (block != current_block->next) + { + /* Find the Block containing the given node */ + if (&(block->nodes[0]) <= node && &(block->nodes[BLOCK_TRANX_NODES]) >= node) + { + /* All Blocks before the given node are put into the rear */ + if (first_block != block) + { + last_block->next= first_block; + first_block= block; + last_block= prev_block; + last_block->next= NULL; + free_blocks(); + } + return 0; + } + prev_block= block; + block= block->next; + } + + /* Node does not find should never happen */ + DBUG_ASSERT(0); + return 1; + } + +private: + uint reserved_blocks; + + /** + A sequence memory which contains BLOCK_TRANX_NODES TranxNodes. + + BLOCK_TRANX_NODES The number of TranxNodes which are in a Block. + + next Every Block has a 'next' pointer which points to the next Block. + These linking Blocks constitute a Block link table. + */ + struct Block { + Block *next; + TranxNode nodes[BLOCK_TRANX_NODES]; + }; + + /** + The 'first_block' is the head of the Block link table; + */ + Block *first_block; + /** + The 'last_block' is the rear of the Block link table; + */ + Block *last_block; + + /** + current_block always points the Block in the Block link table in + which the last allocated node is. The Blocks before it are all in use + and the Blocks after it are all free. + */ + Block *current_block; + + /** + It always points to the last node which has been allocated in the + current_block. + */ + int last_node; + + /** + How many Blocks are in the Block link table. + */ + uint block_num; + + /** + Allocate a block and then assign it to current_block. + */ + int allocate_block() + { + Block *block= (Block *)my_malloc(sizeof(Block), MYF(0)); + if (block) + { + block->next= NULL; + + if (first_block == NULL) + first_block= block; + else + last_block->next= block; + + /* New Block is always put into the rear */ + last_block= block; + /* New Block is always the current_block */ + current_block= block; + ++block_num; + return 0; + } + return 1; + } + + /** + Free a given Block. + @param block The Block will be freed. + */ + void free_block(Block *block) + { + my_free(block, MYF(0)); + --block_num; + } + + + /** + If there are some free Blocks and the total number of the Blocks in the + Block link table is larger than the 'reserved_blocks', Some free Blocks + will be freed until the total number of the Blocks is equal to the + 'reserved_blocks' or there is only one free Block behind the + 'current_block'. + */ + void free_blocks() + { + if (current_block == NULL || current_block->next == NULL) + return; + + /* One free Block is always kept behind the current block */ + Block *block= current_block->next->next; + while (block_num > reserved_blocks && block != NULL) + { + Block *next= block->next; + free_block(block); + block= next; + } + current_block->next->next= block; + if (block == NULL) + last_block= current_block->next; + } +}; + /** This class manages memory for active transaction list. @@ -37,13 +297,8 @@ extern PSI_cond_key key_ss_cond_COND_bin class ActiveTranx :public Trace { private: - struct TranxNode { - char log_name_[FN_REFLEN]; - my_off_t log_pos_; - struct TranxNode *next_; /* the next node in the sorted list */ - struct TranxNode *hash_next_; /* the next node during hash collision */ - }; + TranxNodeAllocator allocator_; /* These two record the active transaction list in sort order. */ TranxNode *trx_front_, *trx_rear_; @@ -54,24 +309,22 @@ private: inline void assert_lock_owner(); - inline TranxNode* alloc_tranx_node(); - inline unsigned int calc_hash(const unsigned char *key,unsigned int length); unsigned int get_hash_value(const char *log_file_name, my_off_t log_file_pos); int compare(const char *log_file_name1, my_off_t log_file_pos1, - const TranxNode *node2) { + const TranxNode *node2) { return compare(log_file_name1, log_file_pos1, - node2->log_name_, node2->log_pos_); + node2->log_name_, node2->log_pos_); } int compare(const TranxNode *node1, - const char *log_file_name2, my_off_t log_file_pos2) { + const char *log_file_name2, my_off_t log_file_pos2) { return compare(node1->log_name_, node1->log_pos_, - log_file_name2, log_file_pos2); + log_file_name2, log_file_pos2); } int compare(const TranxNode *node1, const TranxNode *node2) { return compare(node1->log_name_, node1->log_pos_, - node2->log_name_, node2->log_pos_); + node2->log_name_, node2->log_pos_); } public: @@ -94,7 +347,7 @@ public: * 0: success; non-zero: error */ int clear_active_tranx_nodes(const char *log_file_name, - my_off_t log_file_pos); + my_off_t log_file_pos); /* Given a position, check to see whether the position is an active * transaction's ending position by probing the hash table. @@ -105,7 +358,7 @@ public: * (file_name, file_position). */ static int compare(const char *log_file_name1, my_off_t log_file_pos1, - const char *log_file_name2, my_off_t log_file_pos2); + const char *log_file_name2, my_off_t log_file_pos2); }; === modified file 'sql/rpl_handler.cc' --- a/sql/rpl_handler.cc 2009-12-05 02:46:29 +0000 +++ b/sql/rpl_handler.cc 2010-01-31 13:37:41 +0000 @@ -190,8 +190,8 @@ int Trans_delegate::after_commit(THD *th { Trans_param param; bool is_real_trans= (all || thd->transaction.all.ha_list == 0); - if (is_real_trans) - param.flags |= TRANS_IS_REAL_TRANS; + + param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0; Trans_binlog_info *log_info= my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO); @@ -218,8 +218,8 @@ int Trans_delegate::after_rollback(THD * { Trans_param param; bool is_real_trans= (all || thd->transaction.all.ha_list == 0); - if (is_real_trans) - param.flags |= TRANS_IS_REAL_TRANS; + + param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0; Trans_binlog_info *log_info= my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO); @@ -228,7 +228,7 @@ int Trans_delegate::after_rollback(THD * param.log_pos= log_info ? log_info->log_pos : 0; int ret= 0; - FOREACH_OBSERVER(ret, after_commit, thd, (¶m)); + FOREACH_OBSERVER(ret, after_rollback, thd, (¶m)); /* This is the end of a real transaction or autocommit statement, we --===============5720571594975708533== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/li-bing.song@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: li-bing.song@stripped # target_branch: file:///home/anders/work/bzrroot/mysql-next-mr-\ # bugfixing/ # testament_sha1: c5f27ca1918125d519f180a8e4e26ae67e13ad3e # timestamp: 2010-01-31 21:42:03 +0800 # source_branch: file:///home/anders/work/bzrroot/mysql-5.1-rep-\ # semisync/ # base_revision_id: aelkin@stripped # # Begin bundle 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 --===============5720571594975708533==--