Fish slow uploads - Final patch
buc
buc at odusz.so-cdu.ru
Wed Dec 8 16:30:13 UTC 2004
Several days ago I have sent a patch which tried to solve too slow
FISH uploads problem. The idea also has been discussed in RedHat
bugzilla <https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=140750> .
Now the solution has changed, and it is the best variant which I could find.
Full description of the issue:
Midnight Commander has a FISH virtual filesystem (FIle transfer over
SHell). There is one old problem in MC implementation of it -- uploads
onto remote system.
To do such an upload, MC should invoke on the remote side a command,
which reads appropriate number of bytes from stdin and store them in the
target file. Initially, `dd' command had been chosen for this purpose.
The decision was such:
( dd bs=4096 count=<size/4096> ; dd bs=<size%4096> count=1 ) | ( cat
>target_file ; cat >/dev/null )
(Note: additional cat to /dev/null is needed to flush input on write
errors).
But unfortunately, this variant appeared unreliable. The design of
`dd' does not assume full filling of input buffers on read (see, for
example, "conv=sync" description in `dd' manual). The design of `ssh' is
those that sometimes data can be written into pipe by portions of
different size. Therefore the part of data could remain not read by `dd'
...
In the current version, the problem is solved as:
dd bs=1 count=<size> | .....
i.e., `dd' reads input byte-by-byte. It is robast, but is very slow and
grabs a lot of cpu time on the remote system.
The better decision is possible.
There is `head' command. It has `-c <number>' option, which does what
we really need. The necessary amount of data is read from stdin reliably.
Unfortunately, the remote system (any *NIX-like) may not have `head'
command, or have another implementation of it. But for such systems we
can still use `dd' .
The first solution was:
( head -c <size> -q - || dd bs=1 count=<size> ) | ( cat >target_file ;
cat >/dev/null )
Either fast `head' is used, or `dd' as a fallback. Using `-q' and `-'
we separate GNU `head' from another `head' implementations, which might
be unreliable (for example, AIX4 has `-c' option but add extra newline
byte after EOF).
But "dd bs=1" seems to be too slow, even for fallback...
The better solution has been found:
1. First, try GNU `head', as the fastest variant:
( head -c %lu -q - ) | ( cat >/%s ; cat >/dev/null )
2. Second, use `dd'-based fallback:
rest=%lu
while [ $rest -gt 0 ]
do
cnt=`expr \( $rest + 255 \) / 256`
n=`dd bs=256 count=$cnt | tee -a /%s | wc -c`
rest=`expr $rest - $n`
done
Notes:
- `bs=256' is used, because more large buffer does not give real effect.
- we do not read tail (dd bs=<remaining> count=1) explicitly,
because MC never send more bytes until receives a status code.
- `expr' is used as most portable way for expressions.
In ideal world, only one `dd' invokation is needed. Unfortunately,
`dd' can receive less bytes than `bs' is, and does not report exact
byte number (only full/partial block counts are reported).
Therefore we use `tee' and then `wc' to count bytes properly.
`dd'-based variant is fast enough, but using of `head' (when
possible) can reduce remote cpu time in several times. Therefore it is
better to try `head' first, anyway.
The final script is as this:
>/%s
res=`exec 3>&1; ( head -c %lu -q - || echo DD >&3 ) | ( cat >/%s; cat >/dev/null)`
[ "$res" = DD ] && {
rest=%lu
while [ $rest -gt 0 ]
do
cnt=`expr \( $rest + 255 \) / 256`
n=`dd bs=256 count=$cnt | tee -a /%s | wc -c`
rest=`expr $rest - $n`
done
}
and similar for file append case, with some little changes.
`echo DD' etc. looks ugly, but it is portable :-)
I have tested both head and fallback successfully with remote host
under Linux, and fallback with remote AIX4. I also checked GNU and some
old (1984) UNIX sources of `dd', `tee', `wc' -- all things should be OK.
--
Dmitry Butskoj <buc AT odusz.so-cdu.ru>
Saint-Petersburg, Russia
Red Hat Certified Engineer 809003662809495
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.midnight-commander.org/pipermail/mc-devel/attachments/20041208/076f034f/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: mc-4.6.1-fish-upload.patch
Type: text/x-patch
Size: 2900 bytes
Desc: not available
URL: <http://lists.midnight-commander.org/pipermail/mc-devel/attachments/20041208/076f034f/attachment.bin>
More information about the mc-devel
mailing list