1.tron货币什么情况
2.如何杀掉空闲事务
3.MySQL 核心模块揭秘 | 13 期 | 回滚到 savepoint
tron货币什么情况
TRON货币目前处于加密货币市场的生生态活跃状态。 TRON是态源一种基于区块链技术的开放源代码项目,旨在构建一个全球性的跑路自由内容娱乐系统。其货币TRONIX是生生态该生态系统中的数字代币,主要用于平台上的态源交易和支付。自推出以来,跑路注入侠源码TRON和TRX都受到了市场的生生态广泛关注,特别是态源在数字货币领域有着一定的影响力。TRON的跑路工作重点是提供一种可行的方案来构建自由、即时和开放的生生态互联网环境。这个项目的态源进展也持续引发业界和投资者的兴趣。而具体表现如何,跑路还需结合市场情况进行分析。生生态 TRON货币的态源市场表现 TRON货币的市场表现与全球加密货币市场紧密相关。在全球市场积极的跑路氛围下,TRON货币的价格可能上涨,并受到更多投资者的追捧。随着越来越多的850游戏源码商家和企业开始接受TRX作为支付方式,其实际应用场景也在不断扩大。此外,TRON生态系统中的其他应用和服务也为其货币的普及提供了支持。然而,与其他加密货币一样,TRX的价格也存在波动性,受到市场需求、监管政策和技术发展等多种因素的影响。投资者在参与时应当充分了解和评估风险。 TRON的技术发展和社区支持 除了市场表现外,TRON的技术发展和社区支持也是其成功的重要因素。TRON团队一直在努力优化其区块链技术,提高系统的可扩展性和性能。此外,拥有一个活跃的社区也是项目成功的重要推动力。社区成员可以通过各种渠道交流和分享经验,为项目提供宝贵的懒猫网 源码反馈和建议。这些都有助于推动TRON货币的长远发展。因此总体来看,TRON货币具有发展潜力但也存在风险,投资者需审慎判断。请注意投资有风险,决策需谨慎。如何杀掉空闲事务
本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: /tech/database/how_to_kill_idle_trx.html 我们经常遇到一个情况,就是网络断开或程序Bug导致COMMIT/ROLLBACK语句没有传到数
本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: /tech/database/how_to_kill_idle_trx.html
我们经常遇到一个情况,就是网络断开或程序Bug导致COMMIT/ROLLBACK语句没有传到数据库,也没有释放线程,但是线上事务锁定等待严重,连接数暴涨,尤其在测试库这种情况很多,线上也偶有发生,于是想为MySQL增加一个杀掉空闲事务的功能。
那么如何实现呢,通过MySQL Server层有很多不确定因素,漫画连载源码最保险还是在存储引擎层实现,我们用的几乎都是InnoDB/XtraDB,所以就基于Percona来修改了,Oracle版的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的bilibili视频源码Yasufumi Kinoshita和Alexey Kopytov提出过纯SELECT事务不应被kill,但通过一个参数控制的方案还没有被Alexey Kopytov接受,作为通用处理我提出了用两个变量分别控制纯读事务的空闲超时时间和有锁事务的空闲超时时间,还在等待Percona的回复,因为这个方案还在测试,就先不开放修改了,当然如果你很熟悉MYSQL源码,我提出这个思路你肯定知道怎么分成这两个参数控制了。
根据这两个需求我们来设计方法,首先想到这个功能肯定是放在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_int_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_int_t last_stmt_start;
...
}
这里有几个函数是自定义的:
ibool innobase_thd_is_idle(const void* thd);
ib_int_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) /*!{
return(((const THD*)thd)->command == COM_SLEEP);
}
extern "C"
ib_int_t
innobase_thd_get_start_time(
const void* thd) /*!{
return((ib_int_t)((const THD*)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
{
....
uint 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结构体了,那个感觉更危险。
MySQL 核心模块揭秘 | 期 | 回滚到 savepoint
深入理解 MySQL,了解如何实现部分回滚操作。本文由技术专家操盛春撰写,他在公众号『一树一溪』分享 MySQL 和 OceanBase 源码研究。本文基于 MySQL 8.0.,InnoDB 存储引擎,探讨核心模块的工作原理。
首先,我们创建测试表并插入数据。关键操作分为四个阶段,编号为 SQL 1 至 SQL 4,其中 SQL 4 是讨论焦点。SQL 2 和 SQL 3 分别产生 undo 日志 0 和 1。
当执行事务时,产生的 binlog 日志在 trx cache 中。回滚整个事务时,需要清除这些日志。然而,实际操作中,binlog 回滚步骤看似简单,却并未执行真正清除,只是为后续的 InnoDB 回滚做准备。
InnoDB 回滚是关键环节,它会根据 undo 日志执行反向操作,恢复事务影响的数据。以 SQL 为例,会从最新的 undo 日志开始回滚,逐条执行反向操作,包括记录的删除。
回滚后,事务的执行状态需要通过提交事务来更新。这不同于 commit 语句,因为回滚操作已经改变了数据,即使从逻辑上看恢复了原样,也需要将 InnoDB 中的修改正式提交。
trx cache 中的 binlog 日志会在 InnoDB 回滚完成后进行清除,这个过程涉及内存 buffer 和磁盘临时文件。binlog 回滚步骤延迟到这个阶段,是因为在事务提交前,binlog 日志并不需要写入持久化存储。
总结起来,MySQL 的部分回滚包括:无实际动作的 binlog 回滚,执行 InnoDB 回滚恢复数据,然后提交 InnoDB 事务,最后清理 trx cache 中的临时 binlog。如果你对文中内容有疑问,欢迎留言交流。
对于 SQL 质量管理,如需更多工具支持,可以了解 SQLE,一个覆盖开发到生产环境的 SQL 管理平台,提供流程自动化和数据质量管理功能。