delete 异常引发异常中断

1421人阅读
我们经常遇到一个情况,就是网络断开或程序Bug导致COMMIT/ROLLBACK语句没有传到数据库,也没有释放线程,但是线上事务锁定等待严重,连接数暴涨,尤其在测试库这种情况很多,线上也偶有发生,于是想为MySQL增加一个杀掉空闲事务的功能。
那么如何实现呢,通过My层有很多不确定因素,最保险还是在存储引擎层实现,我们用的几乎都是InnoDB/XtraDB,所以就基于Percona来修改了,版的MySQL也可以照着修改。
1. 一个事务启动,如果事务内最后一个语句执行完超过一个时间(innodb_idle_trx_timeout),就应该关闭链接。
2. 如果事务是纯读事务,因为不加锁,所以无害,不需要关闭,保持即可。
虽然这个思路被Percona的指出Alexey Kopytov可能存在“Even though SELECT queries do not place row locks by default (there are exceptions), they can still block undo log records from being purged.”的问题,但是我们确实有场景SELECT是绝对不能kill的,除非之后的INSERT/UPDATE/DELETE发生了,所以我根据我们的业务特点来修改。跟Percona的Yasufumi
Kinoshita和Alexey Kopytov提出过纯SELECT事务不应被kill,现在也得到回复他们也同意这么做。
一、在InnoDB层实现
首先想到这个功能肯定是放在InnoDB Master Thread最方便,Master Thread每秒调度一次,可以顺便检查空闲事务,然后关闭,因为在事务中操作trx-&mysql_thd并不安全,所以一般来说最好在InnoDB层换成Thread ID操作,并且InnoDB中除了ha_innodb.cc,其他地方不能饮用THD,所以Master Thread中需要的线程数值,都需要在ha_innodb中计算好传递整型或布尔型返回值给master
thread调用。
首先,我们要增加一个参数:idle_trx_timeout,它表示事务多久没有下一条语句发生就超时关闭。
在storage/innodb_plugin/srv/srv0srv.c的“/* plugin options */”注释下增加如下代码注册idle_trx_timeout变量。
static&MYSQL_SYSVAR_LONG(idle_trx_timeout, srv_idle_trx_timeout,&&PLUGIN_VAR_RQCMDARG,&&&If zero then
this function no effect, if no-zero then wait idle_trx_timeout seconds this transaction will be closed&,&&&Seconds of Idle-Transaction timeout&,&&NULL,&NULL,&0,&0,&LONG_MAX,&0);
代码往下找在innobase_system_variables结构体内加上:
MYSQL_SYSVAR(idle_trx_timeout),
有了这个变量,我们需要在Master Thread(storage/innodb_plugin/srv/srv0srv.c )中执行检测函数查找空闲事务。在loop循环的if (sync_array_print_long_waits(&waiter, &sema)判断后加上这段判断
& &&if&(srv_idle_trx_timeout&&&&trx_sys)&{
& && &&&trx_t*&&trx;
& && &&&time_t&&now;
rescan_idle:
& && &&&now&=&time(NULL);
& && &&&mutex_enter(&kernel_mutex);
& && &&&trx&=&UT_LIST_GET_FIRST(trx_sys-&mysql_trx_list);&#
从当前事务列表里获取第一个事务
& && &&&while&(trx)&{&#
依次循环每个事务进行检查
& && && && &if&(trx-&conc_state&==&TRX_ACTIVE
& && && && && &&&&&trx-&mysql_thd
& && && && && &&&&&innobase_thd_is_idle(trx-&mysql_thd))&{&#
如果事务还活着并且它的状态时空闲的
& && && && && &&&ib_int64_t&&start_time&=&innobase_thd_get_start_time(trx-&mysql_thd);&#
获取线程最后一个语句的开始时间
& && && && && & ulong& && & thd_id&=&innobase_thd_get_thread_id(trx-&mysql_thd);&#获取线程ID,因为存储引擎内直接操作THD不安全
& && && && && &&&if&(trx-&last_stmt_start&!=&start_time)&{&#
如果事务最后语句起始时间不等于线程最后语句起始时间说明事务是新起的
& && && && && && &&&trx-&idle_start&=&now;&#
更新事务的空闲起始时间
& && && && && && &&&trx-&last_stmt_start&=&start_time;&#
更新事务的最后语句起始时间
& && && && && &&}&else&if&(difftime(now,
trx-&idle_start)&# 如果事务不是新起的,已经执行了一部分则判断空闲时间有多长了
& && && && && && && &&&&&srv_idle_trx_timeout)&{&#
如果空闲时间超过阈值则杀掉链接
& && && && && && &&&/* kill the session */
& && && && && && &&&mutex_exit(&kernel_mutex);
& && && && && && &&&thd_kill(thd_id);&# 杀链接
& && && && && && &&&goto&rescan_idle;
& && && && && &&}
& && && && &}
& && && && &trx&=&UT_LIST_GET_NEXT(mysql_trx_list, trx);&#
检查下一个事务
& && &&&mutex_exit(&kernel_mutex);
其中trx中的变量是新加的,在storage/innodb_plugin/include/trx0trx.h的trx_truct加上需要的变量:
struct&trx_struct{...
& &&time_t& && &idle_start;
& & ib_int64_t&&last_stmt_start;
这里有几个函数是自定义的:
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&
innobase_thd_is_idle(
& &&const&void*&thd)
& &&/*!& in: thread handle (THD*) */
& &&return(((const&THD*)thd)-&command&==&COM_SLEEP);
extern&&C&
ib_int64_t
innobase_thd_get_start_time(
& &&const&void*&thd)& &
&&/*!& in: thread handle (THD*) */
& &&return((ib_int64_t)((const&THD*)thd)-&start_time);
extern&&C&
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&THD&&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的操作,有些函数调用是在层次太多看不下去了就简化了。
二、在Server层实现
在MySQL Dev Team一位开发的提示下,这个功能在Server层实现的话,不仅通用性更广,而且更安全。
不得不说active_transaction()是个好函数,可以返回线程是否在一个事务内,就可以在Server端通用的判断事务了。
如何在Server层实现呢,sql/sql_parse.cc的do_command()函数也是个好函数,连接线程会循环调用do_command()来读取并执行命令,在do_command()函数中,会调用my_net_set_read_timeout(net, thd-&variables.net_wait_timeout)来设置线程socket连接超时时间,于是在这里可以下手。
主要代码:
831& &&&This thread will do a blocking read from the client which
832& &&&will be interrupted when the next command is received from
833& &&&the client, the connection is closed or &net_wait_timeout&
834& &&&number of seconds has passed
836& &/* Add For Kill Idle Transaction By P.Linux */
837& &if&(thd-&active_transaction())
839& &&&if&(thd-&variables.trx_idle_timeout&&&0)
841& && & my_net_set_read_timeout(net, thd-&variables.trx_idle_timeout);
842& &&&}&else&if&(thd-&variables.trx_readonly_idle_timeout&&&0&&&&thd-&is_readonly_trx)
844& && & my_net_set_read_timeout(net, thd-&variables.trx_readonly_idle_timeout);
845& &&&}&else&if&(thd-&variables.trx_changes_idle_timeout&&&0&&&&!thd-&is_readonly_trx)
847& && & my_net_set_read_timeout(net, thd-&variables.trx_changes_idle_timeout);
848& &&&}&else&{
849& && & my_net_set_read_timeout(net, thd-&variables.net_wait_timeout);
851& &}&else&{
852& &&&my_net_set_read_timeout(net, thd-&variables.net_wait_timeout);
854& &/* End */
大家看明白了吗?其实这是偷梁换柱,本来在这里是要设置wait_timeout的,先判断线程是不是在事务里,就可以转而实现空闲事务的超时。
trx_idle_timeout 控制所有事务的超时,优先级最高
trx_changes_idle_timeout 控制非只读事务的超时
trx_readonly_idle_timeout 控制只读事务的超时
root@localhost :&(none)&08:39:49&&set&autocommit&=&0&;
Query OK,&0&rows affected&(0.00&sec)
root@localhost :&(none)&08:39:56&&set&trx_idle_timeout&=&5;
Query OK,&0&rows affected&(0.00&sec)
root@localhost :&(none)&08:40:17&&use&perf
Database&changed
root@localhost : perf 08:40:19&&insert&into&perf&(info&)&values('11');
Query OK,&1&row affected&(0.00&sec)
root@localhost : perf 08:40:26&&select&*&from&
ERROR&2006&(HY000): MySQL server has gone awayNo connection.
Trying&to&reconnect...Connection id:& &&6
Current&database: perf
+----+------+
|&id&|&info&|
+----+------+
|&&7&|&aaaa&|
|&&9&|&aaaa&|
|&11&|&aaaa&|
+----+------+
3&rows&in&set&(0.00&sec)
完整的patch这里下载:
这个功能Percona已经决定接受这个方案,比他们自己写的方案既更简单也更安全,功能一样,呵呵。
详细文章发在:
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:20399次
排名:千里之外
转载:29篇
(13)(11)(7)(2)VC程序异常中断的原因_百度知道
VC程序异常中断的原因
自己编写的VC程序,编译调试通过,运行良好,然后关闭运行界面,就弹出一个“已经触发一个中断”的提示,然后断点就停在了下面这个中断处。_CRTIMP void _cdecl _CrtDbg穿耿扁际壮宦憋为铂力Break(
__debugbreak();}求高手指点这可能是什么原因。
提问者采纳
delete 或者free 出错释放了不该释放的内存或者,释放的方法不对1)静穿耿扁际壮宦憋为铂力态变量,全局变量,局部变量的地址,不是动态分配的,如果有指向这些变量的指针,任何释放都是错误的。2)new 分配的指针,用 delete 释放
new[] 分配的指针 ,用
delete[] 释放
malloc 分配的指针
释放3) 全局变量析构出现异常,或者最后析构的变量出现异常。
可能是CArray对象类元素释放的不对,CArray &float,float&&这种的怎么释放呀?谢谢
这种不用管他,他自己会释放。不放心或者内存紧张的话,调用一下 RemoveAll( ),就可以了;CArray&&float,float&&&dx.Add(10.0);&&//&Element&0dx.Add(40.0);&&//&Element&1dx.RemoveAll(&);//主动释放CArray分配的内存,不然dx析构时会自动释放,不会出什么问题。
那,我能问一下,遇到这种问题我应该怎么找问题呀?如果是内存释放问题,我如何确定是什么变量呢?或者如果不是内存泄露问题,应该怎么调试呢?谢谢
如果还在调试状态,找到调用栈窗口,可以具体找到函数,就可以定位出错的代码了。首先,如果调试时错误在系统,而不在你自己的程序的,多半实际是你自己的程序出错。_CrtDbgBreak1)找指针2)找你不熟悉的那些东西,查看是不是用错了,例如CArray ;查看MSDN,知道这些东西的正确使用方法,问题就迎刃而解了。其他类似问题,先看是断言(ASSERT) 还是Debug专用函数的问题;断言意思是说,这个程序运行到这点,必有这个结论,没有就是用错了,不应该调用这段程序。Debug专用函数的,是在问题不明显时,提供的查找问题专用的函数;这个熟悉一下这个函数,是用来做什么的,就很容易找到问题了!!
提问者评价
其他类似问题
为您推荐:
其他3条回答
内存指针访问出错,或者堆内存泄露在debug模式下引发程序崩溃
你特别查找一下,在关闭的时候处理了哪些事件,针对处理的事件中&指针&怎么处理的,通常是指针造成的
看你这个方法有没有写完整
您可能关注的推广回答者:
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
MIPS的异常与中断
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口

我要回帖

更多关于 vc delete 异常 的文章

 

随机推荐