summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Frysinger <vapier@google.com>2022-12-07 09:41:47 -0500
committerMike Frysinger <vapier@google.com>2022-12-08 15:06:24 +0000
commitf159ce0f9ef5bce5a4866a677f0534e3b45a80e2 (patch)
tree0d8410ff9ef7377f9bc2fa7c413bb408cb7cd6c1
parent802cd0c6016d91c62c25178ee1ccc1e78505502c (diff)
downloadgit-repo-f159ce0f9ef5bce5a4866a677f0534e3b45a80e2.tar.gz
sync: fix manifest sync-j handling
Since --jobs defaults to 0, not None, we never pull the value out of the manifest. Treat values of 0 and None the same to fix. Bug: http://b/239712300 Bug: http://b/260908907 Change-Id: I9b1026682072366616825fd72f90bd90c10a252f Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/354254 Tested-by: Mike Frysinger <vapier@google.com> Reviewed-by: Josip Sokcevic <sokcevic@google.com> Reviewed-by: Sam Saccone <samccone@google.com>
-rw-r--r--subcmds/sync.py71
-rw-r--r--tests/test_subcmds_sync.py47
2 files changed, 89 insertions, 29 deletions
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 0c0f0cf3..e4e7a971 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -1190,6 +1190,45 @@ later is required to fix a server side protocol bug.
1190 'release. Use `--auto-gc` instead.', file=sys.stderr) 1190 'release. Use `--auto-gc` instead.', file=sys.stderr)
1191 opt.auto_gc = True 1191 opt.auto_gc = True
1192 1192
1193 def _ValidateOptionsWithManifest(self, opt, mp):
1194 """Like ValidateOptions, but after we've updated the manifest.
1195
1196 Needed to handle sync-xxx option defaults in the manifest.
1197
1198 Args:
1199 opt: The options to process.
1200 mp: The manifest project to pull defaults from.
1201 """
1202 if not opt.jobs:
1203 # If the user hasn't made a choice, use the manifest value.
1204 opt.jobs = mp.manifest.default.sync_j
1205 if opt.jobs:
1206 # If --jobs has a non-default value, propagate it as the default for
1207 # --jobs-xxx flags too.
1208 if not opt.jobs_network:
1209 opt.jobs_network = opt.jobs
1210 if not opt.jobs_checkout:
1211 opt.jobs_checkout = opt.jobs
1212 else:
1213 # Neither user nor manifest have made a choice, so setup defaults.
1214 if not opt.jobs_network:
1215 opt.jobs_network = 1
1216 if not opt.jobs_checkout:
1217 opt.jobs_checkout = DEFAULT_LOCAL_JOBS
1218 opt.jobs = os.cpu_count()
1219
1220 # Try to stay under user rlimit settings.
1221 #
1222 # Since each worker requires at 3 file descriptors to run `git fetch`, use
1223 # that to scale down the number of jobs. Unfortunately there isn't an easy
1224 # way to determine this reliably as systems change, but it was last measured
1225 # by hand in 2011.
1226 soft_limit, _ = _rlimit_nofile()
1227 jobs_soft_limit = max(1, (soft_limit - 5) // 3)
1228 opt.jobs = min(opt.jobs, jobs_soft_limit)
1229 opt.jobs_network = min(opt.jobs_network, jobs_soft_limit)
1230 opt.jobs_checkout = min(opt.jobs_checkout, jobs_soft_limit)
1231
1193 def Execute(self, opt, args): 1232 def Execute(self, opt, args):
1194 manifest = self.outer_manifest 1233 manifest = self.outer_manifest
1195 if not opt.outer_manifest: 1234 if not opt.outer_manifest:
@@ -1240,35 +1279,9 @@ later is required to fix a server side protocol bug.
1240 else: 1279 else:
1241 print('Skipping update of local manifest project.') 1280 print('Skipping update of local manifest project.')
1242 1281
1243 # Now that the manifests are up-to-date, setup the jobs value. 1282 # Now that the manifests are up-to-date, setup options whose defaults might
1244 if opt.jobs is None: 1283 # be in the manifest.
1245 # User has not made a choice, so use the manifest settings. 1284 self._ValidateOptionsWithManifest(opt, mp)
1246 opt.jobs = mp.default.sync_j
1247 if opt.jobs is not None:
1248 # Neither user nor manifest have made a choice.
1249 if opt.jobs_network is None:
1250 opt.jobs_network = opt.jobs
1251 if opt.jobs_checkout is None:
1252 opt.jobs_checkout = opt.jobs
1253 # Setup defaults if jobs==0.
1254 if not opt.jobs:
1255 if not opt.jobs_network:
1256 opt.jobs_network = 1
1257 if not opt.jobs_checkout:
1258 opt.jobs_checkout = DEFAULT_LOCAL_JOBS
1259 opt.jobs = os.cpu_count()
1260
1261 # Try to stay under user rlimit settings.
1262 #
1263 # Since each worker requires at 3 file descriptors to run `git fetch`, use
1264 # that to scale down the number of jobs. Unfortunately there isn't an easy
1265 # way to determine this reliably as systems change, but it was last measured
1266 # by hand in 2011.
1267 soft_limit, _ = _rlimit_nofile()
1268 jobs_soft_limit = max(1, (soft_limit - 5) // 3)
1269 opt.jobs = min(opt.jobs, jobs_soft_limit)
1270 opt.jobs_network = min(opt.jobs_network, jobs_soft_limit)
1271 opt.jobs_checkout = min(opt.jobs_checkout, jobs_soft_limit)
1272 1285
1273 superproject_logging_data = {} 1286 superproject_logging_data = {}
1274 self._UpdateProjectsRevisionId(opt, args, superproject_logging_data, 1287 self._UpdateProjectsRevisionId(opt, args, superproject_logging_data,
diff --git a/tests/test_subcmds_sync.py b/tests/test_subcmds_sync.py
index 13f3f873..236d54e5 100644
--- a/tests/test_subcmds_sync.py
+++ b/tests/test_subcmds_sync.py
@@ -13,11 +13,13 @@
13# limitations under the License. 13# limitations under the License.
14"""Unittests for the subcmds/sync.py module.""" 14"""Unittests for the subcmds/sync.py module."""
15 15
16import os
16import unittest 17import unittest
17from unittest import mock 18from unittest import mock
18 19
19import pytest 20import pytest
20 21
22import command
21from subcmds import sync 23from subcmds import sync
22 24
23 25
@@ -43,6 +45,51 @@ def test_get_current_branch_only(use_superproject, cli_args, result):
43 assert cmd._GetCurrentBranchOnly(opts, cmd.manifest) == result 45 assert cmd._GetCurrentBranchOnly(opts, cmd.manifest) == result
44 46
45 47
48# Used to patch os.cpu_count() for reliable results.
49OS_CPU_COUNT = 24
50
51@pytest.mark.parametrize('argv, jobs_manifest, jobs, jobs_net, jobs_check', [
52 # No user or manifest settings.
53 ([], None, OS_CPU_COUNT, 1, command.DEFAULT_LOCAL_JOBS),
54 # No user settings, so manifest settings control.
55 ([], 3, 3, 3, 3),
56 # User settings, but no manifest.
57 (['--jobs=4'], None, 4, 4, 4),
58 (['--jobs=4', '--jobs-network=5'], None, 4, 5, 4),
59 (['--jobs=4', '--jobs-checkout=6'], None, 4, 4, 6),
60 (['--jobs=4', '--jobs-network=5', '--jobs-checkout=6'], None, 4, 5, 6),
61 (['--jobs-network=5'], None, OS_CPU_COUNT, 5, command.DEFAULT_LOCAL_JOBS),
62 (['--jobs-checkout=6'], None, OS_CPU_COUNT, 1, 6),
63 (['--jobs-network=5', '--jobs-checkout=6'], None, OS_CPU_COUNT, 5, 6),
64 # User settings with manifest settings.
65 (['--jobs=4'], 3, 4, 4, 4),
66 (['--jobs=4', '--jobs-network=5'], 3, 4, 5, 4),
67 (['--jobs=4', '--jobs-checkout=6'], 3, 4, 4, 6),
68 (['--jobs=4', '--jobs-network=5', '--jobs-checkout=6'], 3, 4, 5, 6),
69 (['--jobs-network=5'], 3, 3, 5, 3),
70 (['--jobs-checkout=6'], 3, 3, 3, 6),
71 (['--jobs-network=5', '--jobs-checkout=6'], 3, 3, 5, 6),
72 # Settings that exceed rlimits get capped.
73 (['--jobs=1000000'], None, 83, 83, 83),
74 ([], 1000000, 83, 83, 83),
75])
76def test_cli_jobs(argv, jobs_manifest, jobs, jobs_net, jobs_check):
77 """Tests --jobs option behavior."""
78 mp = mock.MagicMock()
79 mp.manifest.default.sync_j = jobs_manifest
80
81 cmd = sync.Sync()
82 opts, args = cmd.OptionParser.parse_args(argv)
83 cmd.ValidateOptions(opts, args)
84
85 with mock.patch.object(sync, '_rlimit_nofile', return_value=(256, 256)):
86 with mock.patch.object(os, 'cpu_count', return_value=OS_CPU_COUNT):
87 cmd._ValidateOptionsWithManifest(opts, mp)
88 assert opts.jobs == jobs
89 assert opts.jobs_network == jobs_net
90 assert opts.jobs_checkout == jobs_check
91
92
46class GetPreciousObjectsState(unittest.TestCase): 93class GetPreciousObjectsState(unittest.TestCase):
47 """Tests for _GetPreciousObjectsState.""" 94 """Tests for _GetPreciousObjectsState."""
48 95