MariaDB崩溃日志分析及添加分区时崩溃问题求助
MariaDB添加分区时崩溃问题排查
崩溃信息
执行添加分区的SQL时,MariaDB 10.4.6在Windows平台崩溃,异常栈如下:
Thread pointer: 0x1ce1ecc6ab8 Attempting backtrace. You can use the following information to find out where mysqld died. If you see no messages after this, something went terribly wrong... mysqld.exe!ha_partition::read_par_file()[ha_partition.cc:3021] mysqld.exe!ha_partition::get_from_handler_file()[ha_partition.cc:3161] mysqld.exe!ha_partition::initialize_partition()[ha_partition.cc:512] mysqld.exe!partition_create_handler()[ha_partition.cc:185] mysqld.exe!get_new_handler()[handler.cc:302] mysqld.exe!TABLE_SHARE::init_from_binary_frm_image()[table.cc:2025] mysqld.exe!open_table_def()[table.cc:698] mysqld.exe!tdc_acquire_share()[table_cache.cc:842] mysqld.exe!open_table()[sql_base.cc:1905] mysqld.exe!open_and_process_table()[sql_base.cc:3802] mysqld.exe!open_tables()[sql_base.cc:4300] mysqld.exe!mysql_alter_table()[sql_table.cc:9353] mysqld.exe!Sql_cmd_alter_table::execute()[sql_alter.cc:510] mysqld.exe!mysql_execute_command()[sql_parse.cc:6087] mysqld.exe!Prepared_statement::execute()[sql_prepare.cc:4760] mysqld.exe!Prepared_statement::execute_loop()[sql_prepare.cc:4246] mysqld.exe!mysql_sql_stmt_execute()[sql_prepare.cc:3364] mysqld.exe!mysql_execute_command()[sql_parse.cc:3901] mysqld.exe!sp_instr_stmt::exec_core()[sp_head.cc:3652] mysqld.exe!sp_lex_keeper::reset_lex_and_exec_core()[sp_head.cc:3335] mysqld.exe!sp_instr_stmt::execute()[sp_head.cc:3513] mysqld.exe!sp_head::execute()[sp_head.cc:1346] mysqld.exe!sp_head::execute_procedure()[sp_head.cc:2288] mysqld.exe!do_execute_sp()[sql_parse.cc:3005] mysqld.exe!Sql_cmd_call::execute()[sql_parse.cc:3247] mysqld.exe!mysql_execute_command()[sql_parse.cc:6087] mysqld.exe!sp_instr_stmt::exec_core()[sp_head.cc:3652] mysqld.exe!sp_lex_keeper::reset_lex_and_exec_core()[sp_head.cc:3335] mysqld.exe!sp_instr_stmt::execute()[sp_head.cc:3513] mysqld.exe!sp_head::execute()[sp_head.cc:1346] mysqld.exe!sp_head::execute_procedure()[sp_head.cc:2288] mysqld.exe!Event_job_data::execute()[event_data_objects.cc:1459] mysqld.exe!Event_worker_thread::run()[event_scheduler.cc:312] mysqld.exe!event_worker_thread()[event_scheduler.cc:268] mysqld.exe!pthread_start()[my_winthread.c:62] ucrtbase.dll!_configthreadlocale() KERNEL32.DLL!BaseThreadInitThunk() tdll.dll!RtlUserThreadStart() Trying to get some variables. Some pointers may be invalid and cause the dump to abort. Query (0x1ce21cf66b8): alter table mytable add PARTITION (PARTITION t20221103 VALUES LESS THAN (TO_DAYS("2022-11-03")+1)) Connection ID (thread ID): 1649 Status: NOT_KILLED
执行环境:Windows平台,无法调试核心文件。
源码定位
查看MariaDB 10.4.6版本的ha_partition.cc对应代码片段,崩溃发生在读取.par文件的逻辑中:
chksum= 0; for (i= 0; i < len_words; i++) chksum ^= uint4korr((file_buffer) + PAR_WORD_SIZE * i); if (chksum) goto err2; m_tot_parts= uint4korr((file_buffer) + PAR_NUM_PARTS_OFFSET); DBUG_PRINT("info", ("No of parts: %u", m_tot_parts)); tot_partition_words= (m_tot_parts + PAR_WORD_SIZE - 1) / PAR_WORD_SIZE; tot_name_len_offset= file_buffer + PAR_ENGINES_OFFSET + PAR_WORD_SIZE * tot_partition_words; tot_name_words= (uint4korr(tot_name_len_offset) + PAR_WORD_SIZE - 1) / PAR_WORD_SIZE; // <--- crashed here
1. 分析是否正确
你的分析准确:这确实是加载.par文件时的Bug。虽然代码中做了校验和检查,但校验逻辑存在漏洞——当m_tot_parts的值异常时,会导致tot_name_len_offset计算后指向文件缓冲区之外的内存地址,调用uint4korr读取该地址时触发崩溃。说明现有校验未覆盖m_tot_parts的合法性检查,或者.par文件已损坏但校验和未检测出问题。
2. 绕过异常的方法
- 重建分区表迁移数据:先备份原表数据,创建带目标分区的新表,再将数据导入新表,最后替换原表。示例步骤:
-- 创建新分区表 CREATE TABLE new_mytable LIKE mytable; ALTER TABLE new_mytable PARTITION BY RANGE TO_DAYS(your_date_column) ( PARTITION t20221103 VALUES LESS THAN (TO_DAYS("2022-11-03")+1) -- 添加其他需要的分区 ); -- 导入数据 INSERT INTO new_mytable SELECT * FROM mytable; -- 替换原表 RENAME TABLE mytable TO old_mytable, new_mytable TO mytable; - 升级MariaDB版本:该Bug大概率在后续版本中被修复,建议升级到10.4.x系列的最新稳定版,或直接升级到更高版本(如10.5+)。
- 修复或重建.par文件:找到表对应的.par文件(位于MariaDB数据目录下,与.frm文件同目录),先备份该文件,然后删除它,重启MariaDB服务后再尝试执行分区操作。服务重启后会自动重建.par文件。
3. MariaDB崩溃日志分析方法
- 定位崩溃核心函数:从崩溃栈顶部(最靠前的mysqld.exe函数)找到崩溃的具体函数和文件行号,结合源码逻辑分析问题点。
- 结合执行SQL:崩溃时的Query信息直接指出触发崩溃的操作(ALTER TABLE添加分区),缩小问题范围到分区管理相关逻辑。
- 检查源码逻辑:分析崩溃点附近的代码,判断是内存越界、非法指针访问还是数据校验缺失。比如这里是计算偏移时未做边界检查,导致读取了缓冲区外的内存。
- 查看系统和数据库日志:Windows下通过事件查看器查看应用日志,同时检查MariaDB的error.log,看是否有崩溃前的异常信息(如磁盘空间不足、文件权限问题、表结构损坏预警等)。
- 复现验证:在测试环境搭建相同版本的MariaDB,创建相同结构的表,执行相同的SQL,尝试复现崩溃,验证问题原因的推测。
内容的提问来源于stack exchange,提问作者Wotchin
相关产品推荐
相关产品推荐

