mysql - Perl 在打开 gzip 文件时给出“gzip:stdout:Broken pipe”错误,但前提是连接到数据库
问题描述
考虑以下在 Linux 机器上运行的程序,它打开一个 gzip 压缩的输入文件:
#!/usr/bin/env perl
open (my $fileHandle, "-|", "/bin/zcat $ARGV[0]");
my $ff = <$fileHandle>;
close($fileHandle);
这按预期工作(它什么都不做,但不打印错误):
$ bar.pl file.gz
$
现在,如果我使用相同的代码但之前连接到 MySQL 数据库,gzip 会报错(您可以直接运行代码,这是一个开放的数据库,并且凭据可以工作):
#!/usr/bin/env perl
use DBI;
use strict;
use warnings;
my $dsn = "DBI:mysql:database=hg19;host=genome-mysql.cse.ucsc.edu";
my $db = DBI->connect($dsn, 'genomep', 'password');
my $dbResults = $db->prepare("show tables");
my $ret = $dbResults->execute();
$dbResults->finish();
$db->disconnect();
open (my $fileHandle, "-|", "/bin/zcat $ARGV[0]");
my $ff = <$fileHandle>;
close($ff);
运行上述给出:
$ foo.pl file.gz
gzip: stdout: Broken pipe
这显然是一个更复杂的程序的一部分,但我已经设法将其缩减为重现该问题的这个愚蠢的片段。
这是怎么回事?为什么连接到数据库会影响 gzip 的行为?请注意,一切似乎都有效(在实际程序中,我对 gzip 压缩的数据做了一些有用的事情),但为什么我会收到该错误消息?
事实证明,这种行为特定于(稍微)旧版本的 Perl 和/或 DBI。在失败的机器上,我有:
- Ubuntu
- Perl 5,版本 22,subversion 1 (v5.22.1) 为 x86_64-linux-gnu-thread-multi 构建
- DBI 1.634
- DBD 4.033
- 压缩包 1.6
但是,在另外两台机器上它确实有效。这些有:
- Ubuntu
- Perl 5,版本 26,subversion 1 (v5.26.1) 为 x86_64-linux-gnu-thread-multi 构建
- DBI 1.640
- DBD 4.033
- 压缩包 1.6
和
- Arch Linux
- Perl 5,版本 30,subversion 0 (v5.30.0) 为 x86_64-linux-thread-multi 构建
- DBI 1.642
- DBD 4.050
- 压缩包 1.10
解决方案
至少在这里,MySQL 库(可能)似乎正在屏蔽(忽略)SIGPIPE,这就是您所看到的。比较 strace 输出,我在 MySQL 运行中看到这样的一行:
rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[PIPE], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7f78bdf16840}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
事实证明,您可以在没有 MySQL 的情况下轻松复制该行为:
$SIG{PIPE} = 'IGNORE';
open (my $fileHandle, "-|", "/bin/zcat $ARGV[0]");
my $ff = <$fileHandle>;
close($ff);
或者,或者,您可以将信号重置为默认处理程序以使消息消失,即使在连接到 MySQL 之后,通过将其设置为DEFAULT
而不是IGNORE
.
顺便说一下,这是MySQL 库的记录行为:
为了避免在连接终止时中止程序,MySQL 在第一次调用 mysql_library_init()、mysql_init() 或 mysql_connect() 时阻止 SIGPIPE。
(它也可能取决于 gzip 版本;可能某些版本的 gzip 在 init 上设置了信号处理程序。)
最终,您看到的是,如果 gzip 获得 SIGPIPE,它就会退出。如果它从 write 返回一个错误(因为 SIGPIPE 被忽略),它会打印一条错误消息。
推荐阅读
- angular - 是否可以使 Angular ReactiveForm ValidatorFn 设置错误几秒钟?
- javascript - 如何修复 React-Redux 中的“第一次访问渲染数据不可访问,但在第二次访问后可访问以进行渲染”错误
- python - 使用 Sheetfu 读取列
- python-3.x - 从列表中仅提取一个元素并将其作为另一个名称写入 csv
- python-3.x - 手动订购多索引级别
- r - 与值序列不同的矩阵暗名
- python - 从 ModelIndex 扩展 QTreeView 项目
- r - 将非 NA 值堆叠到每列的顶部
- sql-server - 使用 JDBC 从表中选择前 N 行的通用方法
- postgresql - 使用另一个表中的值批量更新一个表