ssh: Work around 'get-bytevector-some' bug.

This works around <https://bugs.gnu.org/30066> and noticeably improves
performance when using GUIX_DAEMON_SOCKET=ssh://HOST (the redirect code
was transferring data to guix-daemon one byte at a time!).

* guix/ssh.scm (remote-daemon-channel)[redirect]: Define 'read!' and use
it instead of 'get-bytevector-some'.
This commit is contained in:
Ludovic Courtès 2018-01-10 17:52:23 +01:00
parent 74a2355254
commit 17af5d51de
No known key found for this signature in database
GPG Key ID: 090B11993D9AEBB5
1 changed files with 23 additions and 10 deletions

View File

@ -101,11 +101,24 @@ Throw an error on failure."
;; Unix-domain sockets but libssh doesn't have an API for that, hence this ;; Unix-domain sockets but libssh doesn't have an API for that, hence this
;; hack. ;; hack.
`(begin `(begin
(use-modules (ice-9 match) (rnrs io ports)) (use-modules (ice-9 match) (rnrs io ports)
(rnrs bytevectors) (system foreign))
(define read!
;; XXX: We would use 'get-bytevector-some' but it always returns a
;; single byte in Guile <= 2.2.3---see <https://bugs.gnu.org/30066>.
;; This procedure works around it.
(let ((proc (pointer->procedure int
(dynamic-func "read" (dynamic-link))
(list int '* size_t))))
(lambda (port bv)
(proc (fileno port) (bytevector->pointer bv)
(bytevector-length bv)))))
(let ((sock (socket AF_UNIX SOCK_STREAM 0)) (let ((sock (socket AF_UNIX SOCK_STREAM 0))
(stdin (current-input-port)) (stdin (current-input-port))
(stdout (current-output-port))) (stdout (current-output-port))
(buffer (make-bytevector 65536)))
(setvbuf stdin _IONBF) (setvbuf stdin _IONBF)
(setvbuf stdout _IONBF) (setvbuf stdout _IONBF)
(connect sock AF_UNIX ,socket-name) (connect sock AF_UNIX ,socket-name)
@ -114,17 +127,17 @@ Throw an error on failure."
(match (select (list stdin sock) '() (list stdin stdout sock)) (match (select (list stdin sock) '() (list stdin stdout sock))
((reads writes ()) ((reads writes ())
(when (memq stdin reads) (when (memq stdin reads)
(match (get-bytevector-some stdin) (match (read! stdin buffer)
((? eof-object?) ((? zero?) ;EOF
(primitive-exit 0)) (primitive-exit 0))
(bv (count
(put-bytevector sock bv)))) (put-bytevector sock buffer 0 count))))
(when (memq sock reads) (when (memq sock reads)
(match (get-bytevector-some sock) (match (read! sock buffer)
((? eof-object?) ((? zero?) ;EOF
(primitive-exit 0)) (primitive-exit 0))
(bv (count
(put-bytevector stdout bv)))) (put-bytevector stdout buffer 0 count))))
(loop)) (loop))
(_ (_
(primitive-exit 1))))))) (primitive-exit 1)))))))