system: 'init' does not recompute the hash of each store item.

Fixes <https://bugs.gnu.org/44760>.

Previously, the 'register-path' call would re-traverse ITEM to compute
its nar hash, even though that hash is already known in the initial
store.  This patch also avoids repeated opening/closing of the
database.

* guix/store/database.scm (call-with-database): Export.
* guix/scripts/system.scm (copy-item): Add 'db' parameter.  Call
'sqlite-register' instead of 'register-path'.
(copy-closure): Remove redundant call to 'references*'.  Call
'call-with-database' and pass the database to 'copy-item'.
This commit is contained in:
Ludovic Courtès 2020-12-11 12:36:52 +01:00
parent 0682cc5936
commit 1574bd82bb
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5
3 changed files with 34 additions and 27 deletions

View file

@ -121,6 +121,7 @@
(eval . (put 'let-system 'scheme-indent-function 1)) (eval . (put 'let-system 'scheme-indent-function 1))
(eval . (put 'with-database 'scheme-indent-function 2)) (eval . (put 'with-database 'scheme-indent-function 2))
(eval . (put 'call-with-database 'scheme-indent-function 1))
(eval . (put 'call-with-transaction 'scheme-indent-function 1)) (eval . (put 'call-with-transaction 'scheme-indent-function 1))
(eval . (put 'with-statement 'scheme-indent-function 3)) (eval . (put 'with-statement 'scheme-indent-function 3))
(eval . (put 'call-with-retrying-transaction 'scheme-indent-function 1)) (eval . (put 'call-with-retrying-transaction 'scheme-indent-function 1))

View file

@ -29,7 +29,9 @@ (define-module (guix scripts system)
#:use-module (guix ui) #:use-module (guix ui)
#:use-module ((guix status) #:select (with-status-verbosity)) #:use-module ((guix status) #:select (with-status-verbosity))
#:use-module (guix store) #:use-module (guix store)
#:autoload (guix store database) (register-path) #:autoload (guix base16) (bytevector->base16-string)
#:autoload (guix store database)
(sqlite-register store-database-file call-with-database)
#:autoload (guix build store-copy) (copy-store-item) #:autoload (guix build store-copy) (copy-store-item)
#:use-module (guix describe) #:use-module (guix describe)
#:use-module (guix grafts) #:use-module (guix grafts)
@ -130,12 +132,11 @@ (define topologically-sorted*
(store-lift topologically-sorted)) (store-lift topologically-sorted))
(define* (copy-item item references target (define* (copy-item item info target db
#:key (log-port (current-error-port))) #:key (log-port (current-error-port)))
"Copy ITEM to the store under root directory TARGET and register it with "Copy ITEM to the store under root directory TARGET and populate DB with the
REFERENCES as its set of references." given INFO, a <path-info> record."
(let ((dest (string-append target item)) (let ((dest (string-append target item)))
(state (string-append target "/var/guix")))
(format log-port "copying '~a'...~%" item) (format log-port "copying '~a'...~%" item)
;; Remove DEST if it exists to make sure that (1) we do not fail badly ;; Remove DEST if it exists to make sure that (1) we do not fail badly
@ -151,41 +152,45 @@ (define* (copy-item item references target
(copy-store-item item target (copy-store-item item target
#:deduplicate? #t) #:deduplicate? #t)
;; Register ITEM; as a side-effect, it resets timestamps, etc. (sqlite-register db
;; Explicitly use "TARGET/var/guix" as the state directory, to avoid #:path item
;; reproducing the user's current settings; see #:references (path-info-references info)
;; <http://bugs.gnu.org/18049>. #:deriver (path-info-deriver info)
(unless (register-path item #:hash (string-append
#:prefix target "sha256:"
#:state-directory state (bytevector->base16-string (path-info-hash info)))
#:references references) #:nar-size (path-info-nar-size info))))
(leave (G_ "failed to register '~a' under '~a'~%")
item target))))
(define* (copy-closure item target (define* (copy-closure item target
#:key (log-port (current-error-port))) #:key (log-port (current-error-port)))
"Copy ITEM and all its dependencies to the store under root directory "Copy ITEM and all its dependencies to the store under root directory
TARGET, and register them." TARGET, and register them."
(mlet* %store-monad ((to-copy (topologically-sorted* (list item))) (mlet* %store-monad ((to-copy (topologically-sorted* (list item)))
(refs (mapm %store-monad references* to-copy)) (info (mapm %store-monad query-path-info* to-copy))
(info (mapm %store-monad query-path-info*
(delete-duplicates
(append to-copy (concatenate refs)))))
(size -> (reduce + 0 (map path-info-nar-size info)))) (size -> (reduce + 0 (map path-info-nar-size info))))
(define progress-bar (define progress-bar
(progress-reporter/bar (length to-copy) (progress-reporter/bar (length to-copy)
(format #f (G_ "copying to '~a'...") (format #f (G_ "copying to '~a'...")
target))) target)))
(define state
(string-append target "/var/guix"))
(check-available-space size target) (check-available-space size target)
;; Explicitly use "TARGET/var/guix" as the state directory to avoid
;; reproducing the user's current settings; see
;; <http://bugs.gnu.org/18049>.
(call-with-database (store-database-file #:prefix target
#:state-directory state)
(lambda (db)
(call-with-progress-reporter progress-bar (call-with-progress-reporter progress-bar
(lambda (report) (lambda (report)
(let ((void (%make-void-port "w"))) (let ((void (%make-void-port "w")))
(for-each (lambda (item refs) (for-each (lambda (item info)
(copy-item item refs target #:log-port void) (copy-item item info target db #:log-port void)
(report)) (report))
to-copy refs)))) to-copy info))))))
(return *unspecified*))) (return *unspecified*)))

View file

@ -39,6 +39,7 @@ (define-module (guix store database)
#:export (sql-schema #:export (sql-schema
%default-database-file %default-database-file
store-database-file store-database-file
call-with-database
with-database with-database
path-id path-id
sqlite-register sqlite-register