#At file:///home/anders/work/bzrroot/mysql-5.1-rep-semisync/ based on revid:li-bing.song@stripped
3128 Li-Bing.Song@stripped 2010-01-22
Bug #50157 Assertion !active_tranxs_->is_tranx_end_pos(..) in ReplSemiSyncMaster::commitTrx
The root cause of the crash is that a TranxNode is freed before it is used.
A TranxNode is created when each time some log events are written into binlog file
and is synchronized. TranxNodes' memories are allocted from mem_root of the current
thread, and will be freed immediately after current statement ending.
from TranxNode list. So the Pointer of the TranxNode in TranxNode list becomes a
wild pointer.
After this patch, TranxNodes are not allocated from mem_root.
added:
plugin/semisync/semisync_node_allocator.h
modified:
mysql-test/suite/rpl/r/rpl_semi_sync_mixed_tables.result
mysql-test/suite/rpl/t/rpl_semi_sync_mixed_tables.test
plugin/semisync/semisync_master.cc
plugin/semisync/semisync_master.h
plugin/semisync/semisync_master_plugin.cc
=== modified file 'mysql-test/suite/rpl/r/rpl_semi_sync_mixed_tables.result'
--- a/mysql-test/suite/rpl/r/rpl_semi_sync_mixed_tables.result 2010-01-20 08:37:18 +0000
+++ b/mysql-test/suite/rpl/r/rpl_semi_sync_mixed_tables.result 2010-01-22 14:59:03 +0000
@@ -15,22 +15,26 @@ CREATE TABLE t2(c1 INT) ENGINE=innodb;
call mtr.add_suppression(".*");
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled = 1;
-SET GLOBAL rpl_semi_sync_master_trace_level= 80;
+SET GLOBAL rpl_semi_sync_master_trace_level= 0;
STOP SLAVE;
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
SET GLOBAL rpl_semi_sync_slave_enabled = 1;
+SET GLOBAL rpl_semi_sync_slave_trace_level= 0;
START SLAVE;
BEGIN;
# Even though it is in a transaction, this statement is binlogged into binlog
# file immediately.
-CREATE TEMPORARY TABLE t1 LIKE t2;
+CREATE TEMPORARY TABLE t1 SELECT c1 FROM t2 where 1=1;
+CREATE TEMPORARY TABLE t3 (c1 INT);
# These statements will not binlogged until the transaction is committed
INSERT INTO t2 VALUES(11);
INSERT INTO t2 VALUES(22);
COMMIT;
+SET GLOBAL rpl_semi_sync_slave_enabled = 0;
UNINSTALL PLUGIN rpl_semi_sync_slave;
+SET GLOBAL rpl_semi_sync_master_enabled = 0;
UNINSTALL PLUGIN rpl_semi_sync_master;
-DROP TABLE t1, t2;
+DROP TABLE t2;
=== modified file 'mysql-test/suite/rpl/t/rpl_semi_sync_mixed_tables.test'
--- a/mysql-test/suite/rpl/t/rpl_semi_sync_mixed_tables.test 2010-01-20 08:37:18 +0000
+++ b/mysql-test/suite/rpl/t/rpl_semi_sync_mixed_tables.test 2010-01-22 14:59:03 +0000
@@ -19,7 +19,7 @@ connection master;
call mtr.add_suppression(".*");
eval INSTALL PLUGIN rpl_semi_sync_master SONAME '$SEMISYNC_MASTER_PLUGIN';
SET GLOBAL rpl_semi_sync_master_enabled = 1;
-SET GLOBAL rpl_semi_sync_master_trace_level= 80;
+SET GLOBAL rpl_semi_sync_master_trace_level= 0;
connection slave;
STOP SLAVE;
@@ -27,6 +27,7 @@ source include/wait_for_slave_to_stop.in
eval INSTALL PLUGIN rpl_semi_sync_slave SONAME '$SEMISYNC_SLAVE_PLUGIN';
SET GLOBAL rpl_semi_sync_slave_enabled = 1;
+SET GLOBAL rpl_semi_sync_slave_trace_level= 0;
START SLAVE;
source include/wait_for_slave_to_start.inc;
@@ -37,6 +38,7 @@ BEGIN;
--echo # Even though it is in a transaction, this statement is binlogged into binlog
--echo # file immediately.
CREATE TEMPORARY TABLE t1 SELECT c1 FROM t2 where 1=1;
+CREATE TEMPORARY TABLE t3 (c1 INT);
--echo
--echo # These statements will not binlogged until the transaction is committed
INSERT INTO t2 VALUES(11);
@@ -45,9 +47,12 @@ COMMIT;
sync_slave_with_master;
--echo
+
+SET GLOBAL rpl_semi_sync_slave_enabled = 0;
UNINSTALL PLUGIN rpl_semi_sync_slave;
connection master;
+SET GLOBAL rpl_semi_sync_master_enabled = 0;
UNINSTALL PLUGIN rpl_semi_sync_master;
-DROP TABLE t1, t2;
+DROP TABLE t2;
source include/master-slave-end.inc;
=== modified file 'plugin/semisync/semisync_master.cc'
--- a/plugin/semisync/semisync_master.cc 2009-12-04 05:43:38 +0000
+++ b/plugin/semisync/semisync_master.cc 2010-01-22 14:59:03 +0000
@@ -65,7 +65,7 @@ static int gettimeofday(struct timeval *
ActiveTranx::ActiveTranx(pthread_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 */
@@ -123,7 +123,7 @@ ActiveTranx::TranxNode* ActiveTranx::all
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));
+ TranxNode *trx_node = allocator_.add_node();
if (trx_node)
{
trx_node->log_name_[0] = '\0';
@@ -271,6 +271,7 @@ int ActiveTranx::clear_active_tranx_node
/* Clear the hash table. */
memset(trx_htb_, 0, num_entries_ * sizeof(TranxNode *));
+ allocator_.delete_all_nodes();
/* Clear the active transaction list. */
if (trx_front_ != NULL)
@@ -311,6 +312,7 @@ int ActiveTranx::clear_active_tranx_node
}
trx_front_ = new_front;
+ allocator_.delete_node_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-04 01:46:33 +0000
+++ b/plugin/semisync/semisync_master.h 2010-01-22 14:59:03 +0000
@@ -19,6 +19,7 @@
#define SEMISYNC_MASTER_H
#include "semisync.h"
+#include "semisync_node_allocator.h"
/**
This class manages memory for active transaction list.
@@ -38,6 +39,7 @@ private:
struct TranxNode *hash_next_; /* the next node during hash collision */
};
+ NodeAllocator<TranxNode> allocator_;
/* These two record the active transaction list in sort order. */
TranxNode *trx_front_, *trx_rear_;
=== modified file 'plugin/semisync/semisync_master_plugin.cc'
--- a/plugin/semisync/semisync_master_plugin.cc 2010-01-20 08:37:18 +0000
+++ b/plugin/semisync/semisync_master_plugin.cc 2010-01-22 14:59:03 +0000
@@ -46,7 +46,10 @@ int repl_semi_request_commit(Trans_param
int repl_semi_report_commit(Trans_param *param)
{
- if (param->log_pos)
+
+ bool is_real_trans= param->flags & TRANS_IS_REAL_TRANS;
+
+ if (is_real_trans && param->log_pos)
{
const char *binlog_name= param->log_file;
return repl_semisync.commitTrx(binlog_name, param->log_pos);
=== added file 'plugin/semisync/semisync_node_allocator.h'
--- a/plugin/semisync/semisync_node_allocator.h 1970-01-01 00:00:00 +0000
+++ b/plugin/semisync/semisync_node_allocator.h 2010-01-22 14:59:03 +0000
@@ -0,0 +1,174 @@
+/* Copyright (C) 2010 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#ifndef SEMISYNC_NODE_ALLOCATOR
+#define SEMISYNC_NODE_ALLOCATOR
+
+/*
+ */
+template <class T> class NodeAllocator
+{
+public:
+ /* init_nodes_ means how many nodes(class T) are in one block */
+ NodeAllocator(uint init_nodes) :
+ init_nodes_(init_nodes), block_size_(init_nodes * sizeof(T)),
+ last_node_(0), head_(0), rear_(0), current_block_(0), block_num_(0) {}
+
+ ~NodeAllocator()
+ {
+ Block *block= head_;
+ while (block != NULL)
+ {
+ Block *next= block->next;
+ free_block(block);
+ block= next;
+ }
+ }
+
+ /*
+ Return a node pointer which follows the last_node_ immediately.
+ */
+ T *add_node()
+ {
+ /* A block is allocated first, if there is no any block existing */
+ if (block_num_ == 0 && allocate_block())
+ return NULL;
+
+ last_node_+= sizeof(T);
+ if (last_node_ == current_block_->end)
+ {
+ current_block_= current_block_->next;
+ /* All blocks are in use, so a new block is allocated */
+ if (current_block_ == NULL && allocate_block())
+ {
+ /* Recovery the last_node_ if allocate_block() fails */
+ last_node_-= sizeof(T);
+ return NULL;
+ }
+ else
+ last_node_= current_block_->begin;
+ }
+ return static_cast<T*>(last_node_);
+ }
+
+ int delete_all_nodes()
+ {
+ last_node_= head_ ? head_->begin : NULL;
+ //free_blocks();
+ return 0;
+ }
+
+ int delete_node_before(T* node)
+ {
+ Block *block;
+ Block *prev_block;
+
+ assert(node != NULL);
+ block= head_;
+ while (block != current_block_->next)
+ {
+ void *p = static_cast<void *>(node);
+ if (block->begin <= p and block->end > p)
+ {
+ if (head_ != block)
+ {
+ rear_->next= head_;
+ head_= block;
+ rear_= prev_block;
+ rear_->next= NULL;
+ //free_blocks();
+ }
+ return 0;
+ }
+ prev_block= block;
+ block= block->next;
+ }
+ return 1;
+ }
+
+private:
+ uint init_nodes_;
+ uint block_size_;
+ void* last_node_;
+
+ struct Block {
+ void *begin;
+ void *end;
+ Block *next;
+ };
+ Block *head_;
+ Block *rear_;
+ Block *current_block_;
+ uint block_num_;
+
+ int allocate_block()
+ {
+ Block *block= (Block *)my_malloc(sizeof(Block), MYF(0));
+ if (block)
+ {
+ block->begin= my_malloc(block_size_, MYF(0));
+ if (block->begin)
+ {
+ block->end= block->begin + block_size_;
+ block->next= NULL;
+
+ if (head_ == NULL)
+ head_= block;
+ else
+ rear_->next= block;
+
+ /* New block always is put at the rear */
+ rear_= block;
+ /* New block always is the current_block_ */
+ current_block_= block;
+ last_node_= block->begin;
+ ++block_num_;
+ return 0;
+ }
+ else
+ my_free(block, MYF(0));
+ }
+ return 1;
+ }
+
+ void free_block(Block *block)
+ {
+ assert(block != NULL || block->begin != NULL);
+ my_free(block->begin, MYF(0));
+ my_free(block, MYF(0));
+ --block_num_;
+ }
+
+ /*
+ */
+ void free_blocks()
+ {
+ if (current_block_ == NULL)
+ return;
+
+ Block *block= current_block_->next;
+ while (block_num_ > 3 && block != NULL)
+ {
+ Block *next= block->next;
+ free_block(block);
+ block= next;
+ }
+ current_block_->next= block;
+ if (block == NULL)
+ rear_= NULL;
+ }
+};
+
+#endif
Attachment: [text/bzr-bundle] bzr/li-bing.song@sun.com-20100122145903-30xn2fzh88sspd49.bundle