背景

上一篇《记一次简单的Oracle离线数据迁移至TiDB过程》说到在使用Lightning导入csv文件到TiDB的时候发现了一个bug,是这样一个过程。

Oracle源库中表名都是大写,经过前文所述的方法导入到TiDB后表名也是保持全大写,数据同步过程非常顺利。
第二天我把整套操作流程教给一位新手朋友,他就挑了一张表用来做实验,结果死活都不行。各种分析和重试都没有效果,就在快要懵逼的时候想到了这个大小写问题,把csv拉出来一看是个全小写的文件名,我尝试着把表名改成大写再导入一次,这次终于成功了。
原来,是这位小伙子用sqluldr2导出表数据的时候把文件名写死了,而且是个小写。。。

那么,说好的TiDB表名不区分大小写呢,怎么用了Lightning就失效了?

Bug重现

上面说的还是有点抽象,我们通过如下的步骤重现一下。

这里我准备的TiDB测试版本是v5.2.2,和前面发现bug的版本一致,Lightning也使用配套的版本。我拿最新的master分支也能复现这个问题。

先创建一张测试表,表名全部用大写:

use test;

create table LIGHTNING_BUG (f1 varchar(50),f2 varchar(50),f3 varchar(50));

再准备一个待导入的csv文件,文件名是test.lightning_bug.csv

111|aaa|%%%
222|bbb|###

Lightning的完整配置文件:

[lightning]
level = "info"
file = "tidb-lightning.log"
index-concurrency = 2
table-concurrency = 5
io-concurrency = 5

[tikv-importer]
backend = "local"
sorted-kv-dir = "/tmp/tidb/lightning_dir"

[mydumper]
data-source-dir = "/tmp/tidb/data"
no-schema = true
filter = ['*.*']

[mydumper.csv]
# 字段分隔符,支持一个或多个字符,默认值为 ','。
separator = '|'
# 引用定界符,设置为空表示字符串未加引号。
delimiter = ''
# 行尾定界字符,支持一个或多个字符。设置为空(默认值)表示 "\n"(换行)和 "\r\n" (回车+换行),均表示行尾。
terminator = ""
# CSV 文件是否包含表头。
# 如果 header = true,将跳过首行。
header = false
# CSV 文件是否包含 NULL。
# 如果 not-null = true,CSV 所有列都不能解析为 NULL。
not-null = false
# 如果 not-null = false(即 CSV 可以包含 NULL),
# 为以下值的字段将会被解析为 NULL。
null = '\N'
# 是否对字段内“\“进行转义
backslash-escape = true
# 如果有行以分隔符结尾,删除尾部分隔符。
trim-last-separator = false

[tidb]
host = "x.x.x.x"
port = 4000
user = "root"
password = ""
status-port = 10080
pd-addr = "x.x.x.x:2379"

[checkpoint]
enable = false

[post-restore]
checksum = false
analyze = false

运行如下命令开始执行导入任务:

./tidb-lightning --config tidb-lightning.toml --check-requirements=false

报错信息:
探索TiDB Lightning的源码来解决发现的bug-LMLPHP

日志里面全部是Info,除了没有正常输出tidb lightning exit以外,看不到任何报错,一幅岁月静好的样子:
探索TiDB Lightning的源码来解决发现的bug-LMLPHP

我认为这里的主要问题是,panic非常不友好,而且提示信息不够明确,虽然说了是空指针异常不过没什么参考价值,当时还被segmentation violation误导了好久,一直怀疑是数据格式有问题。

我意识到这个bug应该不难,于是自己拉了一份TiDB源码开始定位问题。

Lightning的处理流程

Lightning的入口文件是br/cmd/tidb-lightning/main.go,而它的核心实现都放在br/pkg/lightning目录下。

我根据报错的堆栈信息倒推整个Lightning的导入流程,首先定位到restore.go文件第1311行,我看到如下代码:
探索TiDB Lightning的源码来解决发现的bug-LMLPHP

根据直觉,猜测tableInfo是一个nil值,以至于在取tableInfo.Name的时候报出空指针异常。如果是这样的话,证明是表名不存在导致,但我记得表不存在的时候它的报错信息是这样:
探索TiDB Lightning的源码来解决发现的bug-LMLPHP

(实际上在客户现场的时候慌的一批🤣),啃一啃源码也挺有意思的。

文章作者:hoho首发论坛:博客园文章出处:http://www.cnblogs.com/hohoa/欢迎大家一起讨论分享,喜欢请点右下角的推荐鼓励一下,我会有更多的动力来写出好文章!欢迎持续关注我的博客!欢迎转载,转载的时候请注明作者和原文链接。

03-12 00:08