簡體   English   中英

當打開gzip壓縮文件時,Perl給出“ gzip:stdout:管道破裂”錯誤,但僅在連接到數據庫時

[英]Perl gives “gzip: stdout: Broken pipe” error when opening gzipped files, but only if connecting to a DB

考慮以下在Linux機器上運行的程序,該程序將打開壓縮后的輸入文件:

#!/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的行為? 請注意,一切似乎都可以正常工作(在實際程序中,我對壓縮后的數據做了一些有用的事情),但是為什么會收到該錯誤消息?


事實證明,此行為特定於(略)舊版本的Perl和/或DBI。 在失敗的機器上,我有:

  • Ubuntu的
  • 為x86_64-linux-gnu-thread-multi構建的Perl 5,版本22,版本1(v5.22.1)
  • DBI 1.634
  • DBD 4.033
  • gzip 1.6

但是,在另外兩台計算機上,它確實可以工作。 這些有:

  • Ubuntu的
  • 為x86_64-linux-gnu-thread-multi構建的Perl 5,版本26,版本1(v5.26.1)
  • DBI 1.640
  • DBD 4.033
  • gzip 1.6

  • Arch Linux
  • 為x86_64-linux-thread-multi構建的Perl 5,版本30,版本0(v5.30.0)
  • DBI 1.642
  • DBD 4.050
  • gzip 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,它將退出。 如果從寫入返回錯誤(因為SIGPIPE被忽略),它將打印一條錯誤消息。

很可能正在發生以下情況:gzip嘗試寫入管道,您身邊的程序未讀取到eof,關閉管道。 Gzip然后收到一個SIGPIPE,並死於此錯誤消息。 您可以確認發生了嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM