summaryrefslogtreecommitdiff
path: root/lib/spack/spack/database.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spack/spack/database.py')
-rw-r--r--lib/spack/spack/database.py72
1 files changed, 55 insertions, 17 deletions
diff --git a/lib/spack/spack/database.py b/lib/spack/spack/database.py
index 2acc8c2db6..01fb4fc7a5 100644
--- a/lib/spack/spack/database.py
+++ b/lib/spack/spack/database.py
@@ -48,6 +48,12 @@ from spack.filesystem_view import YamlFilesystemView
from spack.util.crypto import bit_length
from spack.version import Version
+
+@contextlib.contextmanager
+def nullcontext(*args, **kwargs):
+ yield
+
+
# TODO: Provide an API automatically retyring a build after detecting and
# TODO: clearing a failure.
@@ -87,6 +93,17 @@ _pkg_lock_timeout = None
# Types of dependencies tracked by the database
_tracked_deps = ('link', 'run')
+# Default list of fields written for each install record
+default_install_record_fields = [
+ 'spec',
+ 'ref_count',
+ 'path',
+ 'installed',
+ 'explicit',
+ 'installation_time',
+ 'deprecated_for',
+]
+
def _now():
"""Returns the time since the epoch"""
@@ -187,17 +204,17 @@ class InstallRecord(object):
else:
return InstallStatuses.MISSING in installed
- def to_dict(self):
- rec_dict = {
- 'spec': self.spec.to_node_dict(),
- 'path': self.path,
- 'installed': self.installed,
- 'ref_count': self.ref_count,
- 'explicit': self.explicit,
- 'installation_time': self.installation_time,
- }
- if self.deprecated_for:
- rec_dict.update({'deprecated_for': self.deprecated_for})
+ def to_dict(self, include_fields=default_install_record_fields):
+ rec_dict = {}
+
+ for field_name in include_fields:
+ if field_name == 'spec':
+ rec_dict.update({'spec': self.spec.to_node_dict()})
+ elif field_name == 'deprecated_for' and self.deprecated_for:
+ rec_dict.update({'deprecated_for': self.deprecated_for})
+ else:
+ rec_dict.update({field_name: getattr(self, field_name)})
+
return rec_dict
@classmethod
@@ -206,9 +223,12 @@ class InstallRecord(object):
d.pop('spec', None)
# Old databases may have "None" for path for externals
- if d['path'] == 'None':
+ if 'path' not in d or d['path'] == 'None':
d['path'] = None
+ if 'installed' not in d:
+ d['installed'] = False
+
return InstallRecord(spec, **d)
@@ -275,7 +295,8 @@ class Database(object):
_prefix_failures = {}
def __init__(self, root, db_dir=None, upstream_dbs=None,
- is_upstream=False):
+ is_upstream=False, enable_transaction_locking=True,
+ record_fields=default_install_record_fields):
"""Create a Database for Spack installations under ``root``.
A Database is a cache of Specs data from ``$prefix/spec.yaml``
@@ -293,6 +314,12 @@ class Database(object):
Caller may optionally provide a custom ``db_dir`` parameter
where data will be stored. This is intended to be used for
testing the Database class.
+
+ This class supports writing buildcache index files, in which case
+ certain fields are not needed in each install record, and no
+ transaction locking is required. To use this feature, provide
+ ``enable_transaction_locking=False``, and specify a list of needed
+ fields in ``record_fields``.
"""
self.root = root
@@ -356,14 +383,23 @@ class Database(object):
# message)
self._fail_when_missing_deps = False
+ if enable_transaction_locking:
+ self._write_transaction_impl = lk.WriteTransaction
+ self._read_transaction_impl = lk.ReadTransaction
+ else:
+ self._write_transaction_impl = nullcontext
+ self._read_transaction_impl = nullcontext
+
+ self._record_fields = record_fields
+
def write_transaction(self):
"""Get a write lock context manager for use in a `with` block."""
- return lk.WriteTransaction(
+ return self._write_transaction_impl(
self.lock, acquire=self._read, release=self._write)
def read_transaction(self):
"""Get a read lock context manager for use in a `with` block."""
- return lk.ReadTransaction(self.lock, acquire=self._read)
+ return self._read_transaction_impl(self.lock, acquire=self._read)
def _failed_spec_path(self, spec):
"""Return the path to the spec's failure file, which may not exist."""
@@ -573,7 +609,8 @@ class Database(object):
This function does not do any locking or transactions.
"""
# map from per-spec hash code to installation record.
- installs = dict((k, v.to_dict()) for k, v in self._data.items())
+ installs = dict((k, v.to_dict(include_fields=self._record_fields))
+ for k, v in self._data.items())
# database includes installation list and version.
@@ -707,7 +744,8 @@ class Database(object):
self.reindex(spack.store.layout)
installs = dict(
- (k, v.to_dict()) for k, v in self._data.items()
+ (k, v.to_dict(include_fields=self._record_fields))
+ for k, v in self._data.items()
)
def invalid_record(hash_key, error):