diff options
author | Harmen Stoppels <me@harmenstoppels.nl> | 2024-10-31 21:58:42 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-31 13:58:42 -0700 |
commit | e3aca49e25e70883fd45ec42c3a43fcd7fda5e29 (patch) | |
tree | b4c98487e824cd0268f2f6a078031a0179ce8b9b /lib | |
parent | 94c29e1cfcc11c2d983513dfb65e3ab5bb13e161 (diff) | |
download | spack-e3aca49e25e70883fd45ec42c3a43fcd7fda5e29.tar.gz spack-e3aca49e25e70883fd45ec42c3a43fcd7fda5e29.tar.bz2 spack-e3aca49e25e70883fd45ec42c3a43fcd7fda5e29.tar.xz spack-e3aca49e25e70883fd45ec42c3a43fcd7fda5e29.zip |
database.py: remove process unsafe update_explicit (#47358)
Fixes an issue reported where `spack env depfile` + `make -j` would
non-deterministically refuse to mark all environment roots explicit.
`update_explicit` had the pattern
```python
rec = self._data[key]
with self.write_transaction():
rec.explicit = explicit
```
but `write_transaction` may reinitialize `self._data`, meaning that
mutating `rec` won't mutate `self._data`, and the changes won't be
persisted.
Instead, use `mark` which has a correct implementation.
Also avoids the essentially incorrect early return in `update_explicit`
which is a pattern I don't think belongs in database.py: it branches on
possibly stale data to realize there is nothing to change, but in reality
it requires a write transaction to know that for a fact, but that would
defeat the purpose. So, leave this optimization to the call site.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/spack/cmd/mark.py | 5 | ||||
-rw-r--r-- | lib/spack/spack/database.py | 20 | ||||
-rw-r--r-- | lib/spack/spack/installer.py | 6 |
3 files changed, 7 insertions, 24 deletions
diff --git a/lib/spack/spack/cmd/mark.py b/lib/spack/spack/cmd/mark.py index 0069008c4f..66a84fb907 100644 --- a/lib/spack/spack/cmd/mark.py +++ b/lib/spack/spack/cmd/mark.py @@ -98,8 +98,9 @@ def do_mark(specs, explicit): specs (list): list of specs to be marked explicit (bool): whether to mark specs as explicitly installed """ - for spec in specs: - spack.store.STORE.db.update_explicit(spec, explicit) + with spack.store.STORE.db.write_transaction(): + for spec in specs: + spack.store.STORE.db.mark(spec, "explicit", explicit) def mark_specs(args, specs): diff --git a/lib/spack/spack/database.py b/lib/spack/spack/database.py index 12f6ac2465..e53dd817a5 100644 --- a/lib/spack/spack/database.py +++ b/lib/spack/spack/database.py @@ -1336,7 +1336,7 @@ class Database: self._data[spec_key] = spec_rec @_autospec - def mark(self, spec: "spack.spec.Spec", key, value) -> None: + def mark(self, spec: "spack.spec.Spec", key: str, value: Any) -> None: """Mark an arbitrary record on a spec.""" with self.write_transaction(): return self._mark(spec, key, value) @@ -1771,24 +1771,6 @@ class Database: if id(rec.spec) not in needed and rec.installed ] - def update_explicit(self, spec, explicit): - """ - Update the spec's explicit state in the database. - - Args: - spec (spack.spec.Spec): the spec whose install record is being updated - explicit (bool): ``True`` if the package was requested explicitly - by the user, ``False`` if it was pulled in as a dependency of - an explicit package. - """ - rec = self.get_record(spec) - if explicit != rec.explicit: - with self.write_transaction(): - message = "{s.name}@{s.version} : marking the package {0}" - status = "explicit" if explicit else "implicit" - tty.debug(message.format(status, s=spec)) - rec.explicit = explicit - class NoUpstreamVisitor: """Gives edges to upstream specs, but does follow edges from upstream specs.""" diff --git a/lib/spack/spack/installer.py b/lib/spack/spack/installer.py index 80fe9f2b03..be09973336 100644 --- a/lib/spack/spack/installer.py +++ b/lib/spack/spack/installer.py @@ -412,7 +412,7 @@ def _process_external_package(pkg: "spack.package_base.PackageBase", explicit: b tty.debug(f"{pre} already registered in DB") record = spack.store.STORE.db.get_record(spec) if explicit and not record.explicit: - spack.store.STORE.db.update_explicit(spec, explicit) + spack.store.STORE.db.mark(spec, "explicit", True) except KeyError: # If not, register it and generate the module file. @@ -1507,8 +1507,8 @@ class PackageInstaller: self._update_installed(task) # Only update the explicit entry once for the explicit package - if task.explicit: - spack.store.STORE.db.update_explicit(task.pkg.spec, True) + if task.explicit and not rec.explicit: + spack.store.STORE.db.mark(task.pkg.spec, "explicit", True) def _cleanup_all_tasks(self) -> None: """Cleanup all tasks to include releasing their locks.""" |