summaryrefslogtreecommitdiff
path: root/plugin
diff options
context:
space:
mode:
authorHe Zhenxing <zhenxing.he@sun.com>2009-12-04 09:46:33 +0800
committerHe Zhenxing <zhenxing.he@sun.com>2009-12-04 09:46:33 +0800
commit16ec25c0a8438473d2273722de37ade855615ea4 (patch)
tree09ee9cda482d9a3f2fc365bd77b66441c765d6c3 /plugin
parentf09129c6beecb20da475b41af1bba948abf826c8 (diff)
downloadmariadb-git-16ec25c0a8438473d2273722de37ade855615ea4.tar.gz
Bug#49020 Semi-sync master crashed with free_pool == NULL, assertion `free_pool_'
Before this patch, semisync assumed transactions running in parallel can not be larger than max_connections, but this is not true when the event scheduler is executing events, and cause semisync run out of preallocated transaction nodes. Fix the problem by allocating transaction nodes dynamically. This patch also fixed a possible deadlock when running UNINSTALL PLUGIN rpl_semi_sync_master and updating in parallel. Fixed by releasing the internal Delegate lock before unlock the plugins.
Diffstat (limited to 'plugin')
-rw-r--r--plugin/semisync/semisync_master.cc84
-rw-r--r--plugin/semisync/semisync_master.h23
2 files changed, 27 insertions, 80 deletions
diff --git a/plugin/semisync/semisync_master.cc b/plugin/semisync/semisync_master.cc
index cc83978ad4e..526797a3c4a 100644
--- a/plugin/semisync/semisync_master.cc
+++ b/plugin/semisync/semisync_master.cc
@@ -63,29 +63,14 @@ static int gettimeofday(struct timeval *tv, void *tz)
*
******************************************************************************/
-ActiveTranx::ActiveTranx(int max_connections,
- pthread_mutex_t *lock,
+ActiveTranx::ActiveTranx(pthread_mutex_t *lock,
unsigned long trace_level)
- : Trace(trace_level), num_transactions_(max_connections),
- num_entries_(max_connections << 1),
+ : Trace(trace_level),
+ num_entries_(max_connections << 1), /* Transaction hash table size
+ * is set to double the size
+ * of max_connections */
lock_(lock)
{
- /* Allocate the memory for the array */
- node_array_ = new TranxNode[num_transactions_];
- for (int idx = 0; idx < num_transactions_; ++idx)
- {
- node_array_[idx].log_pos_ = 0;
- node_array_[idx].hash_next_ = NULL;
- node_array_[idx].next_ = node_array_ + idx + 1;
-
- node_array_[idx].log_name_ = new char[FN_REFLEN];
- node_array_[idx].log_name_[0] = '\x0';
- }
- node_array_[num_transactions_-1].next_ = NULL;
-
- /* All nodes in the array go to the pool initially. */
- free_pool_ = node_array_;
-
/* No transactions are in the list initially. */
trx_front_ = NULL;
trx_rear_ = NULL;
@@ -95,24 +80,13 @@ ActiveTranx::ActiveTranx(int max_connections,
for (int idx = 0; idx < num_entries_; ++idx)
trx_htb_[idx] = NULL;
- sql_print_information("Semi-sync replication initialized for %d "
- "transactions.", num_transactions_);
+ sql_print_information("Semi-sync replication initialized for transactions.");
}
ActiveTranx::~ActiveTranx()
{
- for (int idx = 0; idx < num_transactions_; ++idx)
- {
- delete [] node_array_[idx].log_name_;
- node_array_[idx].log_name_ = NULL;
- }
-
- delete [] node_array_;
delete [] trx_htb_;
-
- node_array_ = NULL;
trx_htb_ = NULL;
- num_transactions_ = 0;
num_entries_ = 0;
}
@@ -143,26 +117,21 @@ unsigned int ActiveTranx::get_hash_value(const char *log_file_name,
ActiveTranx::TranxNode* ActiveTranx::alloc_tranx_node()
{
- TranxNode *ptr = free_pool_;
-
- if (free_pool_)
- {
- free_pool_ = free_pool_->next_;
- ptr->next_ = NULL;
- ptr->hash_next_ = NULL;
- }
- else
+ 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)
{
- /*
- free_pool should never be NULL here, because we have
- max_connections number of pre-allocated nodes.
- */
- sql_print_error("You have encountered a semi-sync bug (free_pool == NULL), "
- "please report to http://bugs.mysql.com");
- assert(free_pool_);
+ trx_node->log_name_[0] = '\0';
+ trx_node->log_pos_= 0;
+ trx_node->next_= 0;
+ trx_node->hash_next_= 0;
}
-
- return ptr;
+ return trx_node;
}
int ActiveTranx::compare(const char *log_file_name1, my_off_t log_file_pos1,
@@ -306,8 +275,6 @@ int ActiveTranx::clear_active_tranx_nodes(const char *log_file_name,
/* Clear the active transaction list. */
if (trx_front_ != NULL)
{
- trx_rear_->next_ = free_pool_;
- free_pool_ = trx_front_;
trx_front_ = NULL;
trx_rear_ = NULL;
}
@@ -326,11 +293,6 @@ int ActiveTranx::clear_active_tranx_nodes(const char *log_file_name,
{
next_node = curr_node->next_;
- /* Put the node in the memory pool. */
- curr_node->next_ = free_pool_;
- free_pool_ = curr_node;
- n_frees++;
-
/* Remove the node from the hash table. */
unsigned int hash_val = get_hash_value(curr_node->log_name_, curr_node->log_pos_);
TranxNode **hash_ptr = &(trx_htb_[hash_val]);
@@ -391,8 +353,7 @@ ReplSemiSyncMaster::ReplSemiSyncMaster()
wait_file_pos_(0),
master_enabled_(false),
wait_timeout_(0L),
- state_(0),
- max_transactions_(0L)
+ state_(0)
{
strcpy(reply_file_name_, "");
strcpy(wait_file_name_, "");
@@ -413,7 +374,6 @@ int ReplSemiSyncMaster::initObject()
/* References to the parameter works after set_options(). */
setWaitTimeout(rpl_semi_sync_master_timeout);
setTraceLevel(rpl_semi_sync_master_trace_level);
- max_transactions_ = (int)max_connections;
/* Mutex initialization can only be done after MY_INIT(). */
pthread_mutex_init(&LOCK_binlog_, MY_MUTEX_INIT_FAST);
@@ -436,9 +396,7 @@ int ReplSemiSyncMaster::enableMaster()
if (!getMasterEnabled())
{
- active_tranxs_ = new ActiveTranx(max_connections,
- &LOCK_binlog_,
- trace_level_);
+ active_tranxs_ = new ActiveTranx(&LOCK_binlog_, trace_level_);
if (active_tranxs_ != NULL)
{
commit_file_name_inited_ = false;
diff --git a/plugin/semisync/semisync_master.h b/plugin/semisync/semisync_master.h
index d2b87745600..bfb1cb74cd0 100644
--- a/plugin/semisync/semisync_master.h
+++ b/plugin/semisync/semisync_master.h
@@ -23,31 +23,26 @@
/**
This class manages memory for active transaction list.
- We record each active transaction with a TranxNode. Because each
- session can only have only one open transaction, the total active
- transaction nodes can not exceed the maximum sessions. Currently
- in MySQL, sessions are the same as connections.
+ We record each active transaction with a TranxNode, each session
+ can have only one open transaction. Because of EVENT, the total
+ active transaction nodes can exceed the maximum allowed
+ connections.
*/
class ActiveTranx
:public Trace {
private:
struct TranxNode {
- char *log_name_;
+ 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 */
};
- /* The following data structure maintains an active transaction list. */
- TranxNode *node_array_;
- TranxNode *free_pool_;
-
/* These two record the active transaction list in sort order. */
TranxNode *trx_front_, *trx_rear_;
TranxNode **trx_htb_; /* A hash table on active transactions. */
- int num_transactions_; /* maximum transactions */
int num_entries_; /* maximum hash table entries */
pthread_mutex_t *lock_; /* mutex lock */
@@ -74,8 +69,7 @@ private:
}
public:
- ActiveTranx(int max_connections, pthread_mutex_t *lock,
- unsigned long trace_level);
+ ActiveTranx(pthread_mutex_t *lock, unsigned long trace_level);
~ActiveTranx();
/* Insert an active transaction node with the specified position.
@@ -177,11 +171,6 @@ class ReplSemiSyncMaster
bool state_; /* whether semi-sync is switched */
- /* The number of maximum active transactions. This should be the same as
- * maximum connections because MySQL does not do connection sharing now.
- */
- int max_transactions_;
-
void lock();
void unlock();
void cond_broadcast();