技术开发 频道

MySQL数据库:如何杀掉空闲事务?

  这里有几个函数是自定义的:

ibool      innobase_thd_is_idle(const void* thd);
ib_int64_t innobase_thd_get_start_time(const void
* thd);
ulong      innobase_thd_get_thread_id(const void
* thd);

   这些函数在ha_innodb.cc中实现,需要在storage/innodb_plugin/srv/srv0srv.c头文件定义下加上这些函数的引用形势。

  然后在storage/innodb_plugin/handler/ha_innodb.cc 中定义这些函数的实现:

extern "C"
ibool
innobase_thd_is_idle(
    const void
* thd)    /*!command == COM_SLEEP);
}
extern "C"
ib_int64_t
innobase_thd_get_start_time(
    const void* thd)    /*!start_time);
}
extern "C"
ulong
innobase_thd_get_thread_id(
        const void* thd)
{
    return(thd_get_thread_id((const THD*) thd));
}

   还有最重要的thd_kill函数负责杀线程的,在sql/sql_class.cc中,找个地方定义这个函数:

void thd_kill(ulong id)
{
    THD
*tmp;
    VOID(pthread_mutex_lock(
&LOCK_thread_count));
    I_List_iterator it(threads);
    
while ((tmp=it++))
    {
        
if (tmp->command == COM_DAEMON || tmp->is_have_lock_thd == 0 )       # 如果是DAEMON线程和不含锁的线程就不要kill了
            
continue;
        
if (tmp->thread_id == id)
        {
            pthread_mutex_lock(
&tmp->LOCK_thd_data);
            
break;
        }
    }
    VOID(pthread_mutex_unlock(
&LOCK_thread_count));
    
if (tmp)
    {
        tmp
->awake(THD::KILL_CONNECTION);
        pthread_mutex_unlock(
&tmp->LOCK_thd_data);
    }
}

   为了存储引擎能引用到这个函数,我们要把它定义到plugin中:

  include/mysql/plugin.h和include/mysql/plugin.h中加上

void thd_kill(unsigned long id);

   如何判定线程的is_have_lock_thd值?首先在THD中加上这个变量(sql/sql_class.cc):

class THD :public Statement,
          
public Open_tables_state
{
....
  uint16    is_have_lock_thd;
....
}

   然后在SQL的必经之路mysql_execute_command拦上一刀,判断是有锁操作发生了还是事务提交或新起事务。

  switch (lex->sql_command) {
  
case SQLCOM_REPLACE:
  
case SQLCOM_REPLACE_SELECT:
  
case SQLCOM_UPDATE:
  
case SQLCOM_UPDATE_MULTI:
  
case SQLCOM_DELETE:
  
case SQLCOM_DELETE_MULTI:
  
case SQLCOM_INSERT:
  
case SQLCOM_INSERT_SELECT:
      thd
->is_have_lock_thd = 1;
      
break;
  
case SQLCOM_COMMIT:
  
case SQLCOM_ROLLBACK:
  
case SQLCOM_XA_START:
  
case SQLCOM_XA_END:
  
case SQLCOM_XA_PREPARE:
  
case SQLCOM_XA_COMMIT:
  
case SQLCOM_XA_ROLLBACK:
  
case SQLCOM_XA_RECOVER:
      thd
->is_have_lock_thd = 0;
      
break;
  }

   为了尽可能兼容Percona的补丁,能引用的都引用了Percona的操作,有些函数调用是在层次太多看不下去了就简化了。

  另外还有一个版本是我自己弄的,在THD中增加了一个last_sql_end_time,在do_command结束后更新last_sql_end_time,然后在事务中拿到THD查看last_sql_end_time就可以得出idle时间,Oracle版我还是建议这么做,不要去改trx_struct结构体了,那个感觉更危险。

0
相关文章