summaryrefslogtreecommitdiff
path: root/buildstream/_artifactcache/artifactcache.py
diff options
context:
space:
mode:
Diffstat (limited to 'buildstream/_artifactcache/artifactcache.py')
-rw-r--r--buildstream/_artifactcache/artifactcache.py126
1 files changed, 68 insertions, 58 deletions
diff --git a/buildstream/_artifactcache/artifactcache.py b/buildstream/_artifactcache/artifactcache.py
index aed6f5fc6..ead44c4ff 100644
--- a/buildstream/_artifactcache/artifactcache.py
+++ b/buildstream/_artifactcache/artifactcache.py
@@ -87,12 +87,10 @@ class ArtifactCache():
self.global_remote_specs = []
self.project_remote_specs = {}
- self.cache_size = None
- self.cache_quota = None
- self.cache_lower_threshold = None
-
- self._required_artifacts = set()
- self._estimated_size = None
+ self._required_artifacts = set() # The artifacts required for this session
+ self._cache_size = None # The current cache size, sometimes it's an estimate
+ self._cache_quota = None # The cache quota
+ self._cache_lower_threshold = None # The target cache size for a cleanup
os.makedirs(self.extractdir, exist_ok=True)
os.makedirs(self.tmpdir, exist_ok=True)
@@ -227,10 +225,16 @@ class ArtifactCache():
#
# Clean the artifact cache as much as possible.
#
+ # Returns:
+ # (int): The size of the cache after having cleaned up
+ #
def clean(self):
artifacts = self.list_artifacts()
- while self.compute_cache_size() >= self.cache_quota - self.cache_lower_threshold:
+ # Do a real computation of the cache size once, just in case
+ self.compute_cache_size()
+
+ while self.get_cache_size() >= self._cache_lower_threshold:
try:
to_remove = artifacts.pop(0)
except IndexError:
@@ -244,7 +248,7 @@ class ArtifactCache():
"Please increase the cache-quota in {}."
.format(self.context.config_origin or default_conf))
- if self.compute_cache_size() > self.cache_quota:
+ if self.get_quota_exceeded():
raise ArtifactError("Cache too full. Aborting.",
detail=detail,
reason="cache-too-full")
@@ -253,12 +257,15 @@ class ArtifactCache():
key = to_remove.rpartition('/')[2]
if key not in self._required_artifacts:
+
+ # Remove the actual artifact, if it's not required.
size = self.remove(to_remove)
- if size:
- self.cache_size -= size
+
+ # Remove the size from the removed size
+ self.set_cache_size(self._cache_size - size)
# This should be O(1) if implemented correctly
- return self.compute_cache_size()
+ return self.get_cache_size()
# compute_cache_size()
#
@@ -269,60 +276,47 @@ class ArtifactCache():
# (int): The size of the artifact cache.
#
def compute_cache_size(self):
- cache_size = self.calculate_cache_size()
-
- # Keep the estimated size updated here
- self._estimated_size = cache_size
+ self._cache_size = self.calculate_cache_size()
- return cache_size
+ return self._cache_size
- # get_approximate_cache_size()
+ # add_artifact_size()
#
- # A cheap method that aims to serve as an upper limit on the
- # artifact cache size.
+ # Adds the reported size of a newly cached artifact to the
+ # overall estimated size.
#
- # The cache size reported by this function will normally be larger
- # than the real cache size, since it is calculated using the
- # pre-commit artifact size, but for very small artifacts in
- # certain caches additional overhead could cause this to be
- # smaller than, but close to, the actual size.
+ # Args:
+ # artifact_size (int): The size to add.
#
- # Nonetheless, in practice this should be safe to use as an upper
- # limit on the cache size.
+ def add_artifact_size(self, artifact_size):
+ cache_size = self.get_cache_size()
+ cache_size += artifact_size
+
+ self.set_cache_size(cache_size)
+
+ # get_cache_size()
#
- # If the cache has built-in constant-time size reporting, please
- # feel free to override this method with a more accurate
- # implementation.
+ # Fetches the cached size of the cache, this is sometimes
+ # an estimate and periodically adjusted to the real size
+ # when a cache size calculation job runs.
+ #
+ # When it is an estimate, the value is either correct, or
+ # it is greater than the actual cache size.
#
# Returns:
# (int) An approximation of the artifact cache size.
#
- def get_approximate_cache_size(self):
- # If we don't currently have an estimate, figure out the real
- # cache size.
- if self._estimated_size is None:
+ def get_cache_size(self):
+
+ # If we don't currently have an estimate, figure out the real cache size.
+ if self._cache_size is None:
stored_size = self._read_cache_size()
if stored_size is not None:
- self._estimated_size = stored_size
+ self._cache_size = stored_size
else:
self.compute_cache_size()
- return self._estimated_size
-
- # add_artifact_size()
- #
- # Adds the reported size of a newly cached artifact to the
- # overall estimated size.
- #
- # Args:
- # artifact_size (int): The size to add.
- #
- def add_artifact_size(self, artifact_size):
- if not self._estimated_size:
- self.compute_cache_size()
-
- self._estimated_size += artifact_size
- self._write_cache_size(self._estimated_size)
+ return self._cache_size
# set_cache_size()
#
@@ -335,11 +329,21 @@ class ArtifactCache():
# cache_size (int): The size to set.
#
def set_cache_size(self, cache_size):
- self._estimated_size = cache_size
- # set_cache_size is called in cleanup, where it may set the cache to None
- if self._estimated_size is not None:
- self._write_cache_size(self._estimated_size)
+ assert cache_size is not None
+
+ self._cache_size = cache_size
+ self._write_cache_size(self._cache_size)
+
+ # get_quota_exceeded()
+ #
+ # Checks if the current artifact cache size exceeds the quota.
+ #
+ # Returns:
+ # (bool): True of the quota is exceeded
+ #
+ def get_quota_exceeded(self):
+ return self.get_cache_size() > self._cache_quota
################################################
# Abstract methods for subclasses to implement #
@@ -583,6 +587,9 @@ class ArtifactCache():
#
# Writes the given size of the artifact to the cache's size file
#
+ # Args:
+ # size (int): The size of the artifact cache to record
+ #
def _write_cache_size(self, size):
assert isinstance(size, int)
size_file_path = os.path.join(self.context.artifactdir, CACHE_SIZE_FILE)
@@ -594,6 +601,9 @@ class ArtifactCache():
# Reads and returns the size of the artifact cache that's stored in the
# cache's size file
#
+ # Returns:
+ # (int): The size of the artifact cache, as recorded in the file
+ #
def _read_cache_size(self):
size_file_path = os.path.join(self.context.artifactdir, CACHE_SIZE_FILE)
@@ -643,13 +653,13 @@ class ArtifactCache():
stat = os.statvfs(artifactdir_volume)
available_space = (stat.f_bsize * stat.f_bavail)
- cache_size = self.get_approximate_cache_size()
+ cache_size = self.get_cache_size()
# Ensure system has enough storage for the cache_quota
#
# If cache_quota is none, set it to the maximum it could possibly be.
#
- # Also check that cache_quota is atleast as large as our headroom.
+ # Also check that cache_quota is at least as large as our headroom.
#
if cache_quota is None: # Infinity, set to max system storage
cache_quota = cache_size + available_space
@@ -675,8 +685,8 @@ class ArtifactCache():
# if we end up writing more than 2G, but hey, this stuff is
# already really fuzzy.
#
- self.cache_quota = cache_quota - headroom
- self.cache_lower_threshold = self.cache_quota / 2
+ self._cache_quota = cache_quota - headroom
+ self._cache_lower_threshold = self._cache_quota / 2
# _configured_remote_artifact_cache_specs():