Commit Graph

41 Commits

Author SHA1 Message Date
Ludovic Courtès
13a7d2a538
database: Validate #:nar-size and #:time when registering store items.
* guix/store/database.scm (assert-integer): New procedure.
(update-or-insert): Use it to validate NAR-SIZE and TIME.
* tests/store-database.scm ("sqlite-register with incorrect size"): New
test.
2021-01-31 21:49:58 +01:00
Ludovic Courtès
9c4869fe9c
database: Remove workarounds unnecessary with guile-sqlite3 0.1.2.
* guix/store/database.scm (sqlite-exec, sqlite-finalize): Remove.
2021-01-31 21:49:58 +01:00
Ludovic Courtès
9e6fe0e08f
database: Honor 'SOURCE_DATE_EPOCH'.
* guix/store/database.scm (timestamp): New procedure.
(sqlite-register): Use it as the default for #:time.
(register-items): Likewise for #:registeration-time.
2020-12-15 17:32:11 +01:00
Ludovic Courtès
3169c93903
database: Remove 'register-path'.
* guix/store/database.scm (register-path): Remove.
* tests/store-database.scm ("register-path"): Rename to...
("register-items"): ... this, and use 'register-items' instead of
'register-path'.
("register-path, directory"): Rename to...
("register-items, directory"): ... this, and use 'register-items'
instead of 'register-path'.
("register-path with unregistered references"): Rename to...
("sqlite-register with unregistered references"): ... this.
2020-12-15 17:32:11 +01:00
Ludovic Courtès
1574bd82bb
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'.
2020-12-15 17:32:11 +01:00
Ludovic Courtès
0682cc5936
database: Remove #:deduplicate? and #:reset-timestamps? from 'register-path'.
* guix/store/database.scm (register-path): Remove #:deduplicate?
and #:reset-timestamps?.
* guix/scripts/system.scm (copy-item): Adjust accordingly.
* tests/store-database.scm ("register-path")
("register-path, directory"): Call 'reset-timestamps'.
2020-12-15 17:32:11 +01:00
Ludovic Courtès
0793833c59
database: Remove #:deduplicate? from 'register-items'.
It is now up to the caller to deduplicate store contents.

* guix/store/database.scm (register-items): Remove #:deduplicate?
parameter and call to 'deduplicate'.
(register-path): Call 'deduplicate' when #:deduplicate? is true.
* gnu/build/image.scm (register-closure): Adjust call accordingly.
* gnu/build/vm.scm (register-closure): Likewise.
* guix/nar.scm (finalize-store-file): Likewise.
* guix/scripts/pack.scm (store-database): Likewise.
2020-12-15 17:32:11 +01:00
Ludovic Courtès
dea1ee1fd7
database: Remove #:reset-timestamps? from 'register-items'.
The assumption now is that the caller took care of resetting timestamps
and permissions.

* guix/store/database.scm (register-items): Remove #:reset-timestamps?
parameter and the call to 'reset-timestamps'.
(register-path): Adjust accordingly and add call to 'reset-timestamps'.
* gnu/build/image.scm (register-closure): Remove #:reset-timestamps?
parameter to 'register-items'.
* gnu/build/vm.scm (register-closure): Likewise.
* guix/nar.scm (finalize-store-file): Adjust accordingly.
* guix/scripts/pack.scm (store-database)[build]: Likewise.
2020-12-15 17:32:10 +01:00
Ludovic Courtès
e9edaf3639
database: Remove unnecessary module imports.
* guix/store/database.scm: Remove unnecessary imports added in
4b9eecd322e566783369795ebea63a479b51f486.
2020-12-08 21:40:05 +01:00
Christopher Baines
2932591b8a
database: register-items: reduce transaction scope.
It was made transactional in a4678c6ba18d8dbd79d931f80426eebf61be7ebe, with
the reasoning to prevent broken intermediate states from being visible. I
think this means something like an entry being in ValidPaths, but the Refs not
being inserted.

Using a transaction for this makes sense, but I think using one single
transaction for the whole register-items call is unnecessary to avoid broken
states from being visible, and could block other writes to the store database
while register-items is running. Because the deduplication and resetting
timestamps happens within the transaction as well, even though these things
don't involve the database, writes to the database will still be blocked while
this is happening.

To reduce the potential for register-items to block other writers to the
database for extended periods, this commit moves the transaction to just wrap
the call to sqlite-register. This is the one place where writes occur, so that
should prevent the broken intermediate states issue above. The one difference
this will make is some of the registered items will be visible to other
connections while others may be still being added. I think this is OK, as it's
equivalent to just registering different items.

* guix/store/database.scm (register-items): Reduce transaction scope.

Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2020-09-14 10:51:26 +02:00
Caleb Ristvedt
a05c31ab30
database: document extra registration requirements.
It's necessary that store items be locked and protected from garbage
collection while they are being registered.  This documents that.

* guix/store/database.scm (register-path, register-items): document GC
  protection and locking requirements.

Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2020-09-14 10:51:26 +02:00
Jan (janneke) Nieuwenhuizen
4b9eecd322
image: Do not set journal_model=WAL for the Hurd.
This fixes <https://bugs.gnu.org/42151>.

* gnu/system/images/hurd.scm (hurd-initialize-root-partition): Use #:wal-mode #f
in call to ...
* gnu/build/image.scm (initialize-root-partition): ... this, add #:wal-mode?
parameter, pass it to ...
(register-closure): ... this, add #:wal-mode? parameter, pass it to ...
* guix/store/database.scm (with-database): ... this, add #:wal-mode?
parameter, pass it to ...
(call-with-database): ... this, add #:wal-mode? parameter; when
set to #f, do not set journal_model=WAL.
2020-07-11 16:34:01 +02:00
Ludovic Courtès
97a46055ca
database: 'register-items' takes an open database.
* guix/store/database.scm (store-database-directory)
(store-database-file): New procedures.
(call-with-database): Add call to 'mkdir-p'.
(register-items): Add 'db' parameter and remove #:state-directory and #:schema.
(register-path): Use 'store-database-file' and 'with-database', and
parameterize SQL-SCHEMA.
* gnu/build/image.scm (register-closure): Likewise.
* gnu/build/vm.scm (register-closure): Likewise.
* guix/scripts/pack.scm (store-database)[build]: Likewise.
2020-06-18 14:48:17 +02:00
Caleb Ristvedt
8971f626f2
database: separate transaction-handling and retry-handling.
Previously call-with-transaction would both retry when SQLITE_BUSY errors were
thrown and do what its name suggested (start and rollback/commit a
transaction).  This changes it to do only what its name implies, which
simplifies its implementation.  Retrying is provided by the new
call-with-SQLITE_BUSY-retrying procedure.

* guix/store/database.scm (call-with-transaction): no longer restarts, new
  #:restartable? argument controls whether "begin" or "begin immediate" is
  used.
  (call-with-SQLITE_BUSY-retrying, call-with-retrying-transaction,
  call-with-retrying-savepoint): new procedures.
  (register-items): use call-with-retrying-transaction to preserve old
  behavior.

* .dir-locals.el (call-with-retrying-transaction,
  call-with-retrying-savepoint): add indentation information.
2020-06-10 21:54:35 -05:00
Caleb Ristvedt
37545de4a3
database: ensure update-or-insert is run within a transaction
update-or-insert can break if an insert occurs between when it decides whether
to update or insert and when it actually performs that operation.  Putting the
check and the update/insert operation in the same transaction ensures that the
update/insert will only succeed if no other write has occurred in the middle.

* guix/store/database.scm (call-with-savepoint): new procedure.
  (update-or-insert): use call-with-savepoint to ensure the read and the
  insert/update occur within the same transaction.
2020-06-10 21:54:35 -05:00
Caleb Ristvedt
5d6e225528
database: rewrite query procedures in terms of with-statement.
Most of our queries would fail to finalize their statements properly if sqlite
returned an error during their execution.  This resolves that, and also makes
them somewhat more concise as a side-effect.

This also makes some small changes to improve certain queries where behavior
was strange or overly verbose.

* guix/store/database.scm (call-with-statement): new procedure.
  (with-statement): new macro.
  (last-insert-row-id, path-id, update-or-insert, add-references): rewrite to
  use with-statement.
  (update-or-insert): factor last-insert-row-id out of the end of both
  branches.
  (add-references): remove pointless last-insert-row-id call.

* .dir-locals.el (with-statement): add indenting information.
2020-06-10 21:54:35 -05:00
Caleb Ristvedt
3cd92a855e
database: work around guile-sqlite3 bug preventing statement reset
guile-sqlite3 provides statement caching, making it unnecessary for sqlite to
keep re-preparing statements that are frequently used.  Unfortunately it
doesn't quite emulate the semantics of sqlite_finalize properly, because it
doesn't cause a commit if the statement being finalized is the last "active"
statement (see https://notabug.org/guile-sqlite3/guile-sqlite3/issues/12).  We
work around this by wrapping sqlite-finalize with our own version that ensures
sqlite-reset is called, which does The Right Thing™.

* guix/store/database.scm (sqlite-finalize): new procedure that shadows the
  sqlite-finalize from (sqlite3).
2020-06-10 21:54:32 -05:00
Ludovic Courtès
7fa6155b23
database: 'reset-timestamps' can optionally preserve permissions.
* guix/store/database.scm (reset-timestamps): Add
 #:preserve-permissions? and honor it.
2020-04-11 20:48:12 +02:00
Caleb Ristvedt
a4678c6ba1
database: Make 'register-items' transactional.
* guix/store/database.scm (SQLITE_BUSY, register-output-sql): New variables.
(add-references): Don't try finalizing after each use, only after all the
uses (otherwise a finalized statement would be used if #:cache? was #f).
(call-with-transaction): New procedure.
(register-items): Use call-with-transaction to prevent broken intermediate
states from being visible.

* .dir-locals.el (call-with-transaction): indent it.

Signed-off-by: Ludovic Courtès <ludo@gnu.org>
2019-03-07 00:00:18 +01:00
Ludovic Courtès
bdf860c2e9
database: Use "write-ahead log" mode and set a long "busy timeout".
This should avoid "database is locked" errors when there's a lot of
concurrency, for instance when offloading simultaneously a lot of
builds.

* guix/store/database.scm (call-with-database): Add two 'sqlite-exec'
calls to set 'journal_mode' and 'busy_timeout'.
2018-12-21 23:50:13 +01:00
Ludovic Courtès
60e1c1099f
Update Guile-SQLite3 URL everywhere.
* README: Update Guile-SQLite3 URL.
* doc/guix.texi (Requirements): Likewise.
* guix/store/database.scm (sqlite-exec): Likewise.
* m4/guix.m4 (GUIX_CHECK_GUILE_SQLITE3): Likewise.
2018-11-23 15:42:00 +01:00
Ludovic Courtès
1afe1985f5
nar: Access the database instead of connecting to the daemon.
* guix/store/database.scm (%default-database-file): New variable.
(path-id): Export.
* guix/nar.scm (finalize-store-file): Use 'with-database' instead of
'with-store', and use 'path-id' instead of 'valid-path?'.
2018-11-13 14:59:45 +01:00
Ludovic Courtès
bb3b6ccb05
database: Register each store item only once.
Fixes <https://bugs.gnu.org/32600>.
Reported by Leo Famulari.

* guix/store/database.scm (register-items): Check whether TO-REGISTER is
in DB by calling 'path-id',  and skip the reset-timestamps,
registration, and deduplication phases when it is.
2018-09-23 23:34:17 +02:00
Ludovic Courtès
f0addd6461
database: 'register-items' shows a progress bar.
* guix/store/database.scm (register-items): Add #:log-port.  Use
'progress-reporter/bar' to show a progress report.
(register-path): Pass #:log-port to 'register-items'.
2018-09-23 23:34:16 +02:00
Ludovic Courtès
e475211869
database: Reset timestamps to one second after the Epoch.
Previously, store items registered in the database by this code (for
instance, store items retrieved by 'guix offload' and passed to
'restore-file-set') would have an mtime of 0 instead of 1.

This would cause problems for things like .go files: Guile would
consider them to be older than the corresponding .scm file, and
consequently it would ignore them and possibly use another (incorrect)
.go file.

Reported by Ricardo Wurmus.

* guix/store/database.scm (reset-timestamps): Pass 1, not 0, to
'utime'.
* tests/store-database.scm ("register-path"): Check the mtime of FILE
and REF.
2018-07-20 15:01:33 +02:00
Ludovic Courtès
e5e5119855
database: 'reset-timestamps' now correctly handles symlinks.
* guix/store/database.scm (reset-timestamps): Use 'utime' with
AT_SYMLINK_NOFOLLOW for symlinks.
2018-07-03 17:50:04 +02:00
Ludovic Courtès
eb9fe97495
database: Allow for deterministic database construction.
Fixes <https://bugs.gnu.org/21073>.

* guix/store/database.scm (sqlite-register): Add #:time.
(%epoch): New variable.
(register-items): Add #:registration-time.  Pass #:time to
'sqlite-register'.
* gnu/build/install.scm (register-closure): Pass #:registration-time.
2018-06-14 11:17:00 +02:00
Ludovic Courtès
078c2329c0
install: Use 'reset-timestamps' from (guix store database).
* gnu/build/install.scm (reset-timestamps): Remove.
* gnu/build/vm.scm: Use 'reset-timestamps' from (guix store database).
2018-06-14 11:17:00 +02:00
Ludovic Courtès
31a63be878
database: Add 'register-items'.
* guix/build/store-copy.scm (store-info): Export.
* guix/store/database.scm (register-items): New procedure.
(register-path): Implement in terms of 'register-items'.
* gnu/build/install.scm (register-closure): Use 'register-items' instead
of 'for-each' and 'register-path'.
2018-06-14 11:17:00 +02:00
Ludovic Courtès
ef1297e8c7
database: 'sqlite-register' takes a database, not a file name.
* guix/store/database.scm (sqlite-register): Remove #:db-file and add
'db' parameter.  Remove #:schema and 'parameterize'.
(register-path): Wrap 'sqlite-register' call in 'with-database' and in
'parameterize'.
* tests/store-database.scm ("new database")
("register-path with unregistered references"): Adjust accordingly.
2018-06-14 11:17:00 +02:00
Ludovic Courtès
49c393ccaa
database: 'reset-timestamps' sets file permissions as well.
* guix/store/database.scm (reset-timestamps): Add 'chmod' calls.
2018-06-14 11:16:59 +02:00
Ludovic Courtès
122a6cad7d
database: Replace existing entries in Refs.
* guix/store/database.scm (add-reference-sql): Add "OR REPLACE".
2018-06-14 11:16:59 +02:00
Ludovic Courtès
4bd86f0d62
database: Add #:reset-timestamps? to 'register-path'.
* guix/store/database.scm (register-path): Add #:reset-timestamps? and
honor it.
2018-06-14 11:16:59 +02:00
Ludovic Courtès
b85e2ff484
database: Remove extra SQL parameter in 'update-or-insert'.
* guix/store/database.scm (update-or-insert): Remove extra #:path
parameter.
2018-06-14 11:16:59 +02:00
Ludovic Courtès
866ee8c66a
database: 'register-path' creates the database directory if needed.
* guix/store/database.scm (register-path): Call 'mkdir-p'.
2018-06-14 11:16:59 +02:00
Ludovic Courtès
33fddb763a
database: Provide a way to specify the schema location.
* guix/store/database.scm (sqlite-register): Add #:schema.  Parameterize
'sql-schema' based on this.
(register-path): Add #:schema and pass it to 'sqlite-register'.
2018-06-14 11:16:59 +02:00
Ludovic Courtès
f8f9f7cabc
database: Fail registration when encountering unregistered references.
* guix/store/database.scm (add-reference-sql): Remove nested SELECT.
(add-references): Expect REFERENCES to be a list of ids.
(sqlite-register): Call 'path-id' for each of REFERENCES and pass it to
'add-references'.
* tests/store-database.scm ("register-path with unregistered references"):
New test.
2018-06-14 11:16:58 +02:00
Ludovic Courtès
3931c76154
database: 'with-database' can now initialize new databases.
* nix/libstore/schema.sql: Rename to...
* guix/store/schema.sql: ... this.
* Makefile.am (nobase_dist_guilemodule_DATA): Add it.
* nix/local.mk (%D%/libstore/schema.sql.hh): Adjust accordingly.
* guix/store/database.scm (sql-schema): New variable.
(sqlite-exec, initialize-database, call-with-database): New procedures.
(with-database): Rewrite in terms of 'call-with-database'.
* tests/store-database.scm ("new database"): New test.
* guix/self.scm (compiled-guix)[*core-modules*]: Add 'schema.sql' to
 #:extra-files.
2018-06-14 11:16:58 +02:00
Caleb Ristvedt
bf5bf5778c
Add (guix store deduplication).
* guix/store/database.scm (register-path): Add #:deduplicate? and call
'deduplicate' when it's true.
(counting-wrapper-port, nar-sha256): Move to...
* guix/store/deduplication.scm: ... here.  New file.
* tests/store-deduplication.scm: New file.
* Makefile.am (STORE_MODULES): Add deduplication.scm.
(SCM_TESTS) [HAVE_GUILE_SQLITE3]: Add store-deduplication.scm.

Co-authored-by: Ludovic Courtès <ludo@gnu.org>
2018-06-01 15:35:54 +02:00
Ludovic Courtès
285cc75c31
database: 'register-path' resets timestamps.
* guix/store/database.scm (reset-timestamps): New procedure.
(register-path): Use it.
2018-06-01 15:35:45 +02:00
Caleb Ristvedt
7f9d184d9b
Add (gnu store database).
* guix/config.scm.in (%store-database-directory): New variable.
* guix/store/database.scm: New file.
* tests/store-database.scm: New file.
* Makefile.am (STORE_MODULES): New variable.
(MODULES, MODULES_NOT_COMPILED): Adjust accordingly.
(SCM_TESTS) [HAVE_GUILE_SQLITE3]: Add tests/store-database.scm.

Co-authored-by: Ludovic Courtès <ludo@gnu.org>
2018-06-01 15:35:32 +02:00