summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Baines <mail@cbaines.net>2024-05-11 17:53:20 +0100
committerChristopher Baines <mail@cbaines.net>2024-05-13 19:31:17 +0100
commit3db1a8341c815af3673c367518fbb193f5592864 (patch)
treee598b06a59d95c4943ec7983d2605fbd3fa2c23c
parent1632fd0f1b1ef6e55e495161d4a056d7164b8581 (diff)
store: Add with-store/non-blocking.
For some applications, it's important to establish a non-blocking connection rather than just making the socket non-blocking after the connection is established. This is because there is I/O on the socket that will block during the handshake. I've noticed this blocking during the handshake causing issues in the build coordinator for example. This commit adds a new with-store variant to avoid changing the behaviour of with-store/open-connection to ensure that this change can't break anything that depends on the blocking nature of the socket. * guix/store.scm (open-unix-domain-socket, open-inet-socket): Take #:non-blocking? and use SOCK_NONBLOCK when calling socket if appropriate. (connect-to-daemon, open-connection, call-with-store): Take #:non-blocking? and pass it on. (with-store/non-blocking): New syntax rule. * .dir-locals.el (scheme-mode): Add entry for with-store/non-blocking. Change-Id: I8225762b78448bc1f7b698c8de5d736e13f577bf
-rw-r--r--.dir-locals.el1
-rw-r--r--guix/store.scm55
2 files changed, 40 insertions, 16 deletions
diff --git a/.dir-locals.el b/.dir-locals.el
index d2f6037afe7..d0c25b867b5 100644
--- a/.dir-locals.el
+++ b/.dir-locals.el
@@ -88,6 +88,7 @@
88 (eval . (put 'manifest-pattern 'scheme-indent-function 0)) 88 (eval . (put 'manifest-pattern 'scheme-indent-function 0))
89 (eval . (put 'substitute-keyword-arguments 'scheme-indent-function 1)) 89 (eval . (put 'substitute-keyword-arguments 'scheme-indent-function 1))
90 (eval . (put 'with-store 'scheme-indent-function 1)) 90 (eval . (put 'with-store 'scheme-indent-function 1))
91 (eval . (put 'with-store/non-blocking 'scheme-indent-function 1))
91 (eval . (put 'with-external-store 'scheme-indent-function 1)) 92 (eval . (put 'with-external-store 'scheme-indent-function 1))
92 (eval . (put 'with-error-handling 'scheme-indent-function 0)) 93 (eval . (put 'with-error-handling 'scheme-indent-function 0))
93 (eval . (put 'with-mutex 'scheme-indent-function 1)) 94 (eval . (put 'with-mutex 'scheme-indent-function 1))
diff --git a/guix/store.scm b/guix/store.scm
index a238cb627ac..58ddaa8d152 100644
--- a/guix/store.scm
+++ b/guix/store.scm
@@ -106,6 +106,7 @@
106 port->connection 106 port->connection
107 close-connection 107 close-connection
108 with-store 108 with-store
109 with-store/non-blocking
109 set-build-options 110 set-build-options
110 set-build-options* 111 set-build-options*
111 valid-path? 112 valid-path?
@@ -462,12 +463,17 @@
462 (file file) 463 (file file)
463 (errno errno)))))))) 464 (errno errno))))))))
464 465
465(define (open-unix-domain-socket file) 466(define* (open-unix-domain-socket file #:key non-blocking?)
466 "Connect to the Unix-domain socket at FILE and return it. Raise a 467 "Connect to the Unix-domain socket at FILE and return it. Raise a
467'&store-connection-error' upon error." 468'&store-connection-error' upon error. If NON-BLOCKING?, make the socket
469non-blocking."
468 (let ((s (with-fluids ((%default-port-encoding #f)) 470 (let ((s (with-fluids ((%default-port-encoding #f))
469 ;; This trick allows use of the `scm_c_read' optimization. 471 ;; This trick allows use of the `scm_c_read' optimization.
470 (socket PF_UNIX (logior SOCK_STREAM SOCK_CLOEXEC) 0))) 472 (socket PF_UNIX
473 (if non-blocking?
474 (logior SOCK_STREAM SOCK_CLOEXEC SOCK_NONBLOCK)
475 (logior SOCK_STREAM SOCK_CLOEXEC))
476 0)))
471 (a (make-socket-address PF_UNIX file))) 477 (a (make-socket-address PF_UNIX file)))
472 478
473 (system-error-to-connection-error file 479 (system-error-to-connection-error file
@@ -478,9 +484,10 @@
478 ;; Default port when connecting to a daemon over TCP/IP. 484 ;; Default port when connecting to a daemon over TCP/IP.
479 44146) 485 44146)
480 486
481(define (open-inet-socket host port) 487(define* (open-inet-socket host port #:key non-blocking?)
482 "Connect to the Unix-domain socket at HOST:PORT and return it. Raise a 488 "Connect to the Unix-domain socket at HOST:PORT and return it. Raise a
483'&store-connection-error' upon error." 489'&store-connection-error' upon error. If NON-BLOCKING?, make the socket
490non-blocking."
484 (define addresses 491 (define addresses
485 (getaddrinfo host 492 (getaddrinfo host
486 (if (number? port) (number->string port) port) 493 (if (number? port) (number->string port) port)
@@ -495,7 +502,10 @@
495 ((ai rest ...) 502 ((ai rest ...)
496 (let ((s (socket (addrinfo:fam ai) 503 (let ((s (socket (addrinfo:fam ai)
497 ;; TCP/IP only 504 ;; TCP/IP only
498 (logior SOCK_STREAM SOCK_CLOEXEC) IPPROTO_IP))) 505 (if non-blocking?
506 (logior SOCK_STREAM SOCK_CLOEXEC SOCK_NONBLOCK)
507 (logior SOCK_STREAM SOCK_CLOEXEC))
508 IPPROTO_IP)))
499 509
500 (catch 'system-error 510 (catch 'system-error
501 (lambda () 511 (lambda ()
@@ -514,9 +524,10 @@
514 (errno (system-error-errno args))))) 524 (errno (system-error-errno args)))))
515 (loop rest))))))))) 525 (loop rest)))))))))
516 526
517(define (connect-to-daemon uri) 527(define* (connect-to-daemon uri #:key non-blocking?)
518 "Connect to the daemon at URI, a string that may be an actual URI or a file 528 "Connect to the daemon at URI, a string that may be an actual URI or a file
519name, and return an input/output port. 529name, and return an input/output port. If NON-BLOCKING?, use a non-blocking
530socket when using the file, unix or guix URI schemes.
520 531
521This is a low-level procedure that does not perform the initial handshake with 532This is a low-level procedure that does not perform the initial handshake with
522the daemon. Use 'open-connection' for that." 533the daemon. Use 'open-connection' for that."
@@ -533,11 +544,13 @@ the daemon. Use 'open-connection' for that."
533 (match (uri-scheme uri) 544 (match (uri-scheme uri)
534 ((or #f 'file 'unix) 545 ((or #f 'file 'unix)
535 (lambda (_) 546 (lambda (_)
536 (open-unix-domain-socket (uri-path uri)))) 547 (open-unix-domain-socket (uri-path uri)
548 #:non-blocking? non-blocking?)))
537 ('guix 549 ('guix
538 (lambda (_) 550 (lambda (_)
539 (open-inet-socket (uri-host uri) 551 (open-inet-socket (uri-host uri)
540 (or (uri-port uri) %default-guix-port)))) 552 (or (uri-port uri) %default-guix-port)
553 #:non-blocking? non-blocking?)))
541 ((? symbol? scheme) 554 ((? symbol? scheme)
542 ;; Try to dynamically load a module for SCHEME. 555 ;; Try to dynamically load a module for SCHEME.
543 ;; XXX: Errors are swallowed. 556 ;; XXX: Errors are swallowed.
@@ -557,7 +570,8 @@ the daemon. Use 'open-connection' for that."
557 (connect uri)) 570 (connect uri))
558 571
559(define* (open-connection #:optional (uri (%daemon-socket-uri)) 572(define* (open-connection #:optional (uri (%daemon-socket-uri))
560 #:key port (reserve-space? #t) cpu-affinity) 573 #:key port (reserve-space? #t) cpu-affinity
574 non-blocking?)
561 "Connect to the daemon at URI (a string), or, if PORT is not #f, use it as 575 "Connect to the daemon at URI (a string), or, if PORT is not #f, use it as
562the I/O port over which to communicate to a build daemon. 576the I/O port over which to communicate to a build daemon.
563 577
@@ -565,7 +579,9 @@ When RESERVE-SPACE? is true, instruct it to reserve a little bit of extra
565space on the file system so that the garbage collector can still operate, 579space on the file system so that the garbage collector can still operate,
566should the disk become full. When CPU-AFFINITY is true, it must be an integer 580should the disk become full. When CPU-AFFINITY is true, it must be an integer
567corresponding to an OS-level CPU number to which the daemon's worker process 581corresponding to an OS-level CPU number to which the daemon's worker process
568for this connection will be pinned. Return a server object." 582for this connection will be pinned. If NON-BLOCKING?, use a non-blocking
583socket when using the file, unix or guix URI schemes. Return a server
584object."
569 (define (handshake-error) 585 (define (handshake-error)
570 (raise (condition 586 (raise (condition
571 (&store-connection-error (file (or port uri)) 587 (&store-connection-error (file (or port uri))
@@ -577,7 +593,8 @@ for this connection will be pinned. Return a server object."
577 ;; really a connection error. 593 ;; really a connection error.
578 (handshake-error))) 594 (handshake-error)))
579 (let*-values (((port) 595 (let*-values (((port)
580 (or port (connect-to-daemon uri))) 596 (or port (connect-to-daemon
597 uri #:non-blocking? non-blocking?)))
581 ((output flush) 598 ((output flush)
582 (buffering-output-port port 599 (buffering-output-port port
583 (make-bytevector 8192)))) 600 (make-bytevector 8192))))
@@ -657,9 +674,10 @@ connection. Use with care."
657 "Close the connection to SERVER." 674 "Close the connection to SERVER."
658 (close (store-connection-socket server))) 675 (close (store-connection-socket server)))
659 676
660(define (call-with-store proc) 677(define* (call-with-store proc #:key non-blocking?)
661 "Call PROC with an open store connection." 678 "Call PROC with an open store connection. Pass NON-BLOCKING? to
662 (let ((store (open-connection))) 679open-connection."
680 (let ((store (open-connection #:non-blocking? non-blocking?)))
663 (define (thunk) 681 (define (thunk)
664 (parameterize ((current-store-protocol-version 682 (parameterize ((current-store-protocol-version
665 (store-connection-version store))) 683 (store-connection-version store)))
@@ -678,6 +696,11 @@ connection. Use with care."
678automatically close the store when the dynamic extent of EXP is left." 696automatically close the store when the dynamic extent of EXP is left."
679 (call-with-store (lambda (store) exp ...))) 697 (call-with-store (lambda (store) exp ...)))
680 698
699(define-syntax-rule (with-store/non-blocking store exp ...)
700 "Bind STORE to an non-blocking open connection to the store and evaluate
701EXPs; automatically close the store when the dynamic extent of EXP is left."
702 (call-with-store (lambda (store) exp ...) #:non-blocking? #t))
703
681(define current-store-protocol-version 704(define current-store-protocol-version
682 ;; Protocol version of the store currently used. XXX: This is a hack to 705 ;; Protocol version of the store currently used. XXX: This is a hack to
683 ;; communicate the protocol version to the build output port. It's a hack 706 ;; communicate the protocol version to the build output port. It's a hack