✨ Cache the extracted core.sqlite_zip database files - #7433
✨ Cache the extracted core.sqlite_zip database files#7433giovannipizzi wants to merge 2 commits into
core.sqlite_zip database files#7433Conversation
The `filepath` of the `core.sqlite_zip` storage backend now also
accepts an `http://` or `https://` URL of an archive hosted online,
e.g.:
verdi profile setup core.sqlite_zip -n --profile-name archive \
--filepath https://example.com/export.aiida
The archive is never downloaded in full. Using the `remotezip` library
(added as a new dependency), only the SQLite database is fetched via
HTTP range requests (to a temporary file, once per Python session, on
first query), and repository files are streamed individually from the
remote zip on demand. Each storage instance opens a single connection
to the remote archive, reused for validation, database extraction and
repository access. The server hosting the archive must support range
requests, and the timeout of the HTTP requests can be changed via the
new `storage.remote_archive_timeout` configuration option (default:
60 seconds).
Since a remote archive cannot be migrated in place, profile setup
fails with a clear error if the archive is not at the target schema
version, instructing the user to download the file and run `verdi
archive migrate` on the local copy. Similarly, resetting a remote
archive raises, and `verdi profile delete --delete-data` reports that
the remote archive is left untouched instead of warning that the file
does not exist.
The `-p/--profile` option of `verdi` now also accepts the location of
a `.aiida` archive, as a `file:///absolute/path` URL of a local
archive or an `http(s)://` URL of a remote one, e.g.:
verdi -p file:///path/to/export.aiida process list -a
verdi -p https://example.com/export.aiida shell
In this case an ephemeral profile is created that mounts the archive
with the read-only `core.sqlite_zip` storage backend, for the duration
of the command only: the profile is never added to the configuration
file and any temporary files are cleaned up when the command finishes.
Archive locations are only accepted by parameters that explicitly opt
in via `ProfileParamType(accept_archive_location=True)`, currently
only the top-level `-p/--profile` option: other profile parameters,
such as the argument of `verdi profile delete`, keep treating such
values as invalid profile names. As part of this,
`aiida.manage.configuration.load_profile` now also accepts a
`Profile` instance in addition to a profile name.
Also fix a latent bug in `FolderBackendRepository.open`, which passed
`encoding` to a binary-mode `open()` call, raising `ValueError` for
any file access on unpacked folder-format archives.
By default, the SQLite database contained in a `core.sqlite_zip` archive is extracted (and for remote archives, downloaded) to a temporary file again for every Python session. This commit adds an optional local cache for the extracted databases, stored in the `cache/sqlite_zip` subdirectory of the AiiDA configuration folder. The cache is content-addressed: entries are named after the CRC-32 checksum and size of the uncompressed database, as recorded in the central directory of the zip archive. Validating a cache entry therefore only requires reading the central directory (for remote archives, a small HTTP range request), never the database itself, and identical archives at different locations share a single entry. No metadata files are needed and concurrent processes are safe: entries are written to a temporary file and moved in place atomically. Since entries are shared between profiles and processes, cached databases are always opened read-only (sqlite URI options `mode=ro&immutable=1`), so no consumer can corrupt an entry for the others. A valid cache entry is always used automatically. The cache is only written when explicitly requested: * `verdi --use-cache -p <profile-or-archive-location> <command>` caches the database for a single invocation. The flag is recorded in the storage configuration of a detached copy of the profile, so it is never persisted to the configuration file. The configuration version is not bumped, since the content of the storage.config is not validated, the keys have safe defaults if not defined, and if AiiDA is downgraded, those new keys are simply ignored. * `verdi profile setup core.sqlite_zip --use-cache` caches the database at setup and records it under the `cached_database` key of the storage configuration in the configuration file, together with the archive schema version under `cached_database_version`. For profiles recording a `cached_database`, a deleted cache entry is transparently recreated on the next load. If instead the archive content no longer matches, loading fails with an error pointing to the new `verdi profile cache-refresh` command, which re-caches the database, updates the recorded keys, and deletes the previously recorded cache entry if no other profile still records it. The new `verdi profile cache-clear` command deletes all cached files; entries are recreated on the next load, although users relying on `--force-cache` with an unreachable archive should be aware that clearing the cache deletes their only usable copy of the data. Finally, the top-level `verdi --force-cache` option uses the recorded cached database directly, without accessing the archive at all. This allows for example working offline with a remote archive, at the cost of the data not being validated (and repository files, which are always read from the archive itself, potentially being unavailable). The recorded schema version is checked even in this mode, so a cached database that predates an upgrade of the archive format fails with a clear error pointing to `verdi profile cache-refresh`, instead of obscure ORM errors.
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
Note 1: developed with support of Claude Fable. Note 2: to be merged only after #7432 |
|
Potential discussion points:
|
|
Seems somewhat to address #7405 - which will help me on MaterialsCloud. |
|
Hi, am currently testing this. I haven't looked into it but a quick optimization would be to check the profile name isn't already taken before downloading anything since at the moment
Additionally - just a thought, perhaps the same sort of feature could be ported to NOTE: After testing - I can comment this "just works" for my current usecase HERE (downloading and querying db), I haven't used the file-access aspect of the PR, nor have i looked at the code at all, however. |
core.sqlite_zip database files
|
Quick thought is to check how this behaves if a user swaps the file at the remote destination with a different AiiDA profile or even a malformed/faulty file... If we understand this behaviour i will know whether i will be able to hotswap .aiida profiles with updated records without causing issues It could also be a potential security risk - someone points users to his web .aiida file and then after connection changes the file to something malicious (a zip bomb or something) ... |
By default, the SQLite database contained in a
core.sqlite_ziparchive is extracted (and for remote archives, downloaded) to a temporary file again for every Python session. This commit adds an optional local cache for the extracted databases, stored in thecache/sqlite_zipsubdirectory of the AiiDA configuration folder.The cache is content-addressed: entries are named after the CRC-32 checksum and size of the uncompressed database, as recorded in the central directory of the zip archive. Validating a cache entry therefore only requires reading the central directory (for remote archives, a small HTTP range request), never the database itself, and identical archives at different locations share a single entry. No metadata files are needed and concurrent processes are safe: entries are written to a temporary file and moved in place atomically. Since entries are shared between profiles and processes, cached databases are always opened read-only (sqlite URI options
mode=ro&immutable=1), so no consumer can corrupt an entry for the others.A valid cache entry is always used automatically. The cache is only written when explicitly requested:
verdi --use-cache -p <profile-or-archive-location> <command>caches the database for a single invocation. The flag is recorded in the storage configuration of a detached copy of the profile, so it is never persisted to the configuration file.The configuration version is not bumped, since the content of the storage.config is not validated, the keys have safe defaults if not defined, and if AiiDA is downgraded, those new keys are simply ignored.
verdi profile setup core.sqlite_zip --use-cachecaches the database at setup and records it under thecached_databasekey of the storage configuration in the configuration file, together with the archive schema version undercached_database_version.For profiles recording a
cached_database, a deleted cache entry is transparently recreated on the next load. If instead the archive content no longer matches, loading fails with an error pointing to the newverdi profile cache-refreshcommand, which re-caches the database, updates the recorded keys, and deletes the previously recorded cache entry if no other profile still records it. The newverdi profile cache-clearcommand deletes all cached files; entries are recreated on the next load, although users relying on--force-cachewith an unreachable archive should be aware that clearing the cache deletes their only usable copy of the data.Finally, the top-level
verdi --force-cacheoption uses the recorded cached database directly, without accessing the archive at all. This allows for example working offline with a remote archive, at the cost of the data not being validated (and repository files, which are always read from the archive itself, potentially being unavailable). The recorded schema version is checked even in this mode, so a cached database that predates an upgrade of the archive format fails with a clear error pointing toverdi profile cache-refresh, instead of obscure ORM errors.