Question

This is weird and I'm not sure who the culprit really is.

I'm doing some scripting, on FreeBSD (6.2)? which makes extensive use of the following ***bash***ism:

do_something <(mysql --skip-column-names -B -e 'select ... from ... where ...;')

... where "do_something is a somewhat crufty utility (in Perl) that won't read from a pipeline. If I use a regular file it works fine. My bash script using things like exec 4< <(...) with these sorts of queries (following by loops of the form while read x y z <&4; do ... never seem to have any issues.

However, Perl (5.8.x) seems to periodically block (apparently forever). I tried changing out the chomp(my $data = <MYDATA>); with a routine that used sysread and I wrote some test cases in Python for comparison. These seem to block far less often than the idiomatic Perl code, but they still do it sometimes. (The Python code using f.read() or os.read(f.fileno()...) seems to behave about equally in this issue).

I've tried reproducing the issue using ... <(cat ...) (where I'm cating the regular file) and that never seems to reproduce that stall.

I've glanced at some ktrace/kdump data ... but I'm far more familiar with Linux strace or even Solaris truss ... so I haven't figured out what's going from there yet, either.

I suppose we can mostly rule out Perl, because I've reproduced the same issue using Python ... I don't see how the bash could be doing anything wrong here (it's just creating a named pipe in /var/tmp/sh-np-xxx and wiring the processes up to that).

What could the mysql shell/utility be doing that might cause this? I don't think I've seen it from anything else (such as cat or dd). I haven't tested this scenario under Linux ... but I've used <(...) (process substitution) for years under Linux and don't recall ever seeing this.

Is it a FreeBSD issue?

Sure I can work around the issue using temporary files ... but I'd sure rather understand why it's doing this (and avoid some of the races and clean-up messiness that temporary files entail).

Any suggestions?

Was it helpful?

Solution

The big difference between operating on the output of mysql and directly on a file is timing. When the perl process is stalled, the big question is: "why is it not making forward progress"? You can use the "l" option to ps to see the wait channel for the perl process; that way you can see if it blocked on a read, or if something else is going on. If it is really blocked on pipe input, I expect the MWCHAN entry for perl to be "piperd".

The same information would be interesting for the mysql process.

What does your Python test code look like?

Another way of writing this while avoiding the bashism is this; that would allow you to rule out bash:

mysql --skip-column-names -B -e 'select ... from ... where ...;' | do_something /dev/stdin

Other interesting questions:

  • Does the --unbuffered option to mysql change anything?

  • Does piping the mysql output through dd change anything? (eg. "perlscript <(mysql ... | dd)

Summary: Need more information.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top