Javier Jardón pushed to branch jennis/quota_declaration_fix at BuildStream / buildstream
Commits:
-
cc2e6ae5
by Valentin David at 2018-11-08T12:41:36Z
-
e578a89f
by Valentin David at 2018-11-08T13:11:10Z
-
c0a8bb66
by Angelos Evripiotis at 2018-11-08T15:49:16Z
-
f7231e90
by Angelos Evripiotis at 2018-11-08T15:49:16Z
-
f7643440
by Angelos Evripiotis at 2018-11-08T15:49:16Z
-
dd5e7b04
by Angelos Evripiotis at 2018-11-08T16:17:04Z
-
fe33e328
by James Ennis at 2018-11-08T17:54:18Z
-
09faf002
by James Ennis at 2018-11-08T17:54:18Z
10 changed files:
- CONTRIBUTING.rst
- buildstream/_artifactcache/artifactcache.py
- buildstream/scriptelement.py
- doc/source/using_config.rst
- + tests/integration/project/elements/script/corruption-2.bst
- + tests/integration/project/elements/script/marked-tmpdir.bst
- + tests/integration/project/elements/script/no-tmpdir.bst
- + tests/integration/project/elements/script/tmpdir.bst
- tests/integration/script.py
- tests/utils/misc.py
Changes:
... | ... | @@ -97,7 +97,13 @@ a new merge request. You can also `create a merge request for an existing branch |
97 | 97 |
You may open merge requests for the branches you create before you are ready
|
98 | 98 |
to have them reviewed and considered for inclusion if you like. Until your merge
|
99 | 99 |
request is ready for review, the merge request title must be prefixed with the
|
100 |
-``WIP:`` identifier.
|
|
100 |
+``WIP:`` identifier. GitLab `treats this specially
|
|
101 |
+<https://docs.gitlab.com/ee/user/project/merge_requests/work_in_progress_merge_requests.html>`_,
|
|
102 |
+which helps reviewers.
|
|
103 |
+ |
|
104 |
+Consider marking a merge request as WIP again if you are taking a while to
|
|
105 |
+address a review point. This signals that the next action is on you, and it
|
|
106 |
+won't appear in a reviewer's search for non-WIP merge requests to review.
|
|
101 | 107 |
|
102 | 108 |
|
103 | 109 |
Organized commits
|
... | ... | @@ -122,6 +128,12 @@ If a commit in your branch modifies behavior such that a test must also |
122 | 128 |
be changed to match the new behavior, then the tests should be updated
|
123 | 129 |
with the same commit, so that every commit passes its own tests.
|
124 | 130 |
|
131 |
+These principles apply whenever a branch is non-WIP. So for example, don't push
|
|
132 |
+'fixup!' commits when addressing review comments, instead amend the commits
|
|
133 |
+directly before pushing. GitLab has `good support
|
|
134 |
+<https://docs.gitlab.com/ee/user/project/merge_requests/versions.html>`_ for
|
|
135 |
+diffing between pushes, so 'fixup!' commits are not necessary for reviewers.
|
|
136 |
+ |
|
125 | 137 |
|
126 | 138 |
Commit messages
|
127 | 139 |
~~~~~~~~~~~~~~~
|
... | ... | @@ -144,6 +156,16 @@ number must be referenced in the commit message. |
144 | 156 |
|
145 | 157 |
Fixes #123
|
146 | 158 |
|
159 |
+Note that the 'why' of a change is as important as the 'what'.
|
|
160 |
+ |
|
161 |
+When reviewing this, folks can suggest better alternatives when they know the
|
|
162 |
+'why'. Perhaps there are other ways to avoid an error when things are not
|
|
163 |
+frobnicated.
|
|
164 |
+ |
|
165 |
+When folks modify this code, there may be uncertainty around whether the foos
|
|
166 |
+should always be frobnicated. The comments, the commit message, and issue #123
|
|
167 |
+should shed some light on that.
|
|
168 |
+ |
|
147 | 169 |
In the case that you have a commit which necessarily modifies multiple
|
148 | 170 |
components, then the summary line should still mention generally what
|
149 | 171 |
changed (if possible), followed by a colon and a brief summary.
|
... | ... | @@ -937,15 +937,22 @@ class ArtifactCache(): |
937 | 937 |
"Invalid cache quota ({}): ".format(utils._pretty_size(cache_quota)) +
|
938 | 938 |
"BuildStream requires a minimum cache quota of 2G.")
|
939 | 939 |
elif cache_quota > cache_size + available_space: # Check maximum
|
940 |
+ if '%' in self.context.config_cache_quota:
|
|
941 |
+ available = (available_space / (stat.f_blocks * stat.f_bsize)) * 100
|
|
942 |
+ available = '{}% of total disk space'.format(round(available, 1))
|
|
943 |
+ else:
|
|
944 |
+ available = utils._pretty_size(available_space)
|
|
945 |
+ |
|
940 | 946 |
raise LoadError(LoadErrorReason.INVALID_DATA,
|
941 | 947 |
("Your system does not have enough available " +
|
942 | 948 |
"space to support the cache quota specified.\n" +
|
943 |
- "You currently have:\n" +
|
|
944 |
- "- {used} of cache in use at {local_cache_path}\n" +
|
|
945 |
- "- {available} of available system storage").format(
|
|
946 |
- used=utils._pretty_size(cache_size),
|
|
947 |
- local_cache_path=self.context.artifactdir,
|
|
948 |
- available=utils._pretty_size(available_space)))
|
|
949 |
+ "\nYou have specified a quota of {quota} total disk space.\n" +
|
|
950 |
+ "- The filesystem containing {local_cache_path} only " +
|
|
951 |
+ "has: {available_size} available.")
|
|
952 |
+ .format(
|
|
953 |
+ quota=self.context.config_cache_quota,
|
|
954 |
+ local_cache_path=self.context.artifactdir,
|
|
955 |
+ available_size=available))
|
|
949 | 956 |
|
950 | 957 |
# Place a slight headroom (2e9 (2GB) on the cache_quota) into
|
951 | 958 |
# cache_quota to try and avoid exceptions.
|
... | ... | @@ -202,7 +202,7 @@ class ScriptElement(Element): |
202 | 202 |
sandbox.set_environment(self.get_environment())
|
203 | 203 |
|
204 | 204 |
# Tell the sandbox to mount the install root
|
205 |
- directories = {'/': False}
|
|
205 |
+ directories = {self.__install_root: False}
|
|
206 | 206 |
|
207 | 207 |
# Mark the artifact directories in the layout
|
208 | 208 |
for item in self.__layout:
|
... | ... | @@ -211,7 +211,10 @@ class ScriptElement(Element): |
211 | 211 |
directories[destination] = item['element'] or was_artifact
|
212 | 212 |
|
213 | 213 |
for directory, artifact in directories.items():
|
214 |
- sandbox.mark_directory(directory, artifact=artifact)
|
|
214 |
+ # Root does not need to be marked as it is always mounted
|
|
215 |
+ # with artifact (unless explicitly marked non-artifact)
|
|
216 |
+ if directory != '/':
|
|
217 |
+ sandbox.mark_directory(directory, artifact=artifact)
|
|
215 | 218 |
|
216 | 219 |
def stage(self, sandbox):
|
217 | 220 |
|
... | ... | @@ -147,6 +147,44 @@ The default mirror is defined by its name, e.g. |
147 | 147 |
``--default-mirror`` command-line option.
|
148 | 148 |
|
149 | 149 |
|
150 |
+Local cache expiry
|
|
151 |
+~~~~~~~~~~~~~~~~~~
|
|
152 |
+BuildStream locally caches artifacts, build trees, log files and sources within a
|
|
153 |
+cache located at ``~/.cache/buildstream`` (unless a $XDG_CACHE_HOME environment
|
|
154 |
+variable exists). When building large projects, this cache can get very large,
|
|
155 |
+thus BuildStream will attempt to clean up the cache automatically by expiring the least
|
|
156 |
+recently *used* artifacts.
|
|
157 |
+ |
|
158 |
+By default, cache expiry will begin once the file system which contains the cache
|
|
159 |
+approaches maximum usage. However, it is also possible to impose a quota on the local
|
|
160 |
+cache in the user configuration. This can be done in two ways:
|
|
161 |
+ |
|
162 |
+1. By restricting the maximum size of the cache directory itself.
|
|
163 |
+ |
|
164 |
+For example, to ensure that BuildStream's cache does not grow beyond 100 GB,
|
|
165 |
+simply declare the following in your user configuration (``~/.config/buildstream.conf``):
|
|
166 |
+ |
|
167 |
+.. code:: yaml
|
|
168 |
+ |
|
169 |
+ cache:
|
|
170 |
+ quota: 100G
|
|
171 |
+ |
|
172 |
+This quota defines the maximum size of the artifact cache in bytes.
|
|
173 |
+Other accepted values are: K, M, G or T (or you can simply declare the value in bytes, without the suffix).
|
|
174 |
+This uses the same format as systemd's
|
|
175 |
+`resource-control <https://www.freedesktop.org/software/systemd/man/systemd.resource-control.html>`_.
|
|
176 |
+ |
|
177 |
+2. By expiring artifacts once the file system which contains the cache exceeds a specified usage.
|
|
178 |
+ |
|
179 |
+To ensure that we start cleaning the cache once we've used 80% of local disk space (on the file system
|
|
180 |
+which mounts the cache):
|
|
181 |
+ |
|
182 |
+.. code:: yaml
|
|
183 |
+ |
|
184 |
+ cache:
|
|
185 |
+ quota: 80%
|
|
186 |
+ |
|
187 |
+ |
|
150 | 188 |
Default configuration
|
151 | 189 |
---------------------
|
152 | 190 |
The default BuildStream configuration is specified here for reference:
|
1 |
+kind: script
|
|
2 |
+ |
|
3 |
+depends:
|
|
4 |
+- filename: base.bst
|
|
5 |
+ type: build
|
|
6 |
+- filename: script/corruption-image.bst
|
|
7 |
+ type: build
|
|
8 |
+ |
|
9 |
+config:
|
|
10 |
+ commands:
|
|
11 |
+ - echo smashed >>/canary
|
1 |
+kind: compose
|
|
2 |
+ |
|
3 |
+depends:
|
|
4 |
+- filename: base.bst
|
|
5 |
+ type: build
|
|
6 |
+ |
|
7 |
+public:
|
|
8 |
+ bst:
|
|
9 |
+ split-rules:
|
|
10 |
+ remove:
|
|
11 |
+ - "/tmp/**"
|
|
12 |
+ - "/tmp"
|
1 |
+kind: filter
|
|
2 |
+ |
|
3 |
+depends:
|
|
4 |
+- filename: script/marked-tmpdir.bst
|
|
5 |
+ type: build
|
|
6 |
+ |
|
7 |
+config:
|
|
8 |
+ exclude:
|
|
9 |
+ - remove
|
|
10 |
+ include-orphans: True
|
|
11 |
+ |
|
12 |
+ |
1 |
+kind: script
|
|
2 |
+ |
|
3 |
+depends:
|
|
4 |
+- filename: script/no-tmpdir.bst
|
|
5 |
+ type: build
|
|
6 |
+ |
|
7 |
+config:
|
|
8 |
+ commands:
|
|
9 |
+ - |
|
|
10 |
+ mkdir -p /tmp/blah
|
... | ... | @@ -184,3 +184,41 @@ def test_regression_cache_corruption(cli, tmpdir, datafiles): |
184 | 184 |
|
185 | 185 |
with open(os.path.join(checkout_after, 'canary')) as f:
|
186 | 186 |
assert f.read() == 'alive\n'
|
187 |
+ |
|
188 |
+ |
|
189 |
+@pytest.mark.datafiles(DATA_DIR)
|
|
190 |
+def test_regression_tmpdir(cli, tmpdir, datafiles):
|
|
191 |
+ project = str(datafiles)
|
|
192 |
+ element_name = 'script/tmpdir.bst'
|
|
193 |
+ |
|
194 |
+ res = cli.run(project=project, args=['build', element_name])
|
|
195 |
+ assert res.exit_code == 0
|
|
196 |
+ |
|
197 |
+ |
|
198 |
+@pytest.mark.datafiles(DATA_DIR)
|
|
199 |
+def test_regression_cache_corruption_2(cli, tmpdir, datafiles):
|
|
200 |
+ project = str(datafiles)
|
|
201 |
+ checkout_original = os.path.join(cli.directory, 'checkout-original')
|
|
202 |
+ checkout_after = os.path.join(cli.directory, 'checkout-after')
|
|
203 |
+ element_name = 'script/corruption-2.bst'
|
|
204 |
+ canary_element_name = 'script/corruption-image.bst'
|
|
205 |
+ |
|
206 |
+ res = cli.run(project=project, args=['build', canary_element_name])
|
|
207 |
+ assert res.exit_code == 0
|
|
208 |
+ |
|
209 |
+ res = cli.run(project=project, args=['checkout', canary_element_name,
|
|
210 |
+ checkout_original])
|
|
211 |
+ assert res.exit_code == 0
|
|
212 |
+ |
|
213 |
+ with open(os.path.join(checkout_original, 'canary')) as f:
|
|
214 |
+ assert f.read() == 'alive\n'
|
|
215 |
+ |
|
216 |
+ res = cli.run(project=project, args=['build', element_name])
|
|
217 |
+ assert res.exit_code == 0
|
|
218 |
+ |
|
219 |
+ res = cli.run(project=project, args=['checkout', canary_element_name,
|
|
220 |
+ checkout_after])
|
|
221 |
+ assert res.exit_code == 0
|
|
222 |
+ |
|
223 |
+ with open(os.path.join(checkout_after, 'canary')) as f:
|
|
224 |
+ assert f.read() == 'alive\n'
|
... | ... | @@ -27,4 +27,5 @@ def test_parse_size_over_1024T(cli, tmpdir): |
27 | 27 |
patched_statvfs = mock_os.mock_statvfs(f_bavail=bavail, f_bsize=BLOCK_SIZE)
|
28 | 28 |
with mock_os.monkey_patch("statvfs", patched_statvfs):
|
29 | 29 |
result = cli.run(project, args=["build", "file.bst"])
|
30 |
- assert "1025T of available system storage" in result.stderr
|
|
30 |
+ failure_msg = 'Your system does not have enough available space to support the cache quota specified.'
|
|
31 |
+ assert failure_msg in result.stderr
|