Skip to content

Commit 4623264

Browse files
quic-kaushiklLUCI
authored andcommitted
Fix submodule initialization in interleaved sync mode
With the introduction of interleaved sync mode, the submodule activation logic broke because the 'has_submodules' attribute was no longer being populated when needed. With this change, each submodule is initialized when it enters the Sync_LocalHalf stage, whereas previously all submodules were initialized at once when the parent repository entered the Sync_LocalHalf stage. The init is now retried if it fails, as submodules may concurrently modify the parent’s git config, potentially causing contention when attempting to obtain a lock on it. This change makes the submodule activation logic more robust and less prone to breakage. Bug: 444366154 Change-Id: I25eca4ea2a6868219045cfa088988eb01ded47d2 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/509041 Reviewed-by: Gavin Mak <[email protected]> Tested-by: Kaushik Lingarkar <[email protected]> Reviewed-by: Nasser Grainawi <[email protected]> Commit-Queue: Kaushik Lingarkar <[email protected]> Reviewed-by: Scott Lee <[email protected]>
1 parent 67383bd commit 4623264

File tree

1 file changed

+31
-14
lines changed

1 file changed

+31
-14
lines changed

project.py

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -642,10 +642,6 @@ def __init__(
642642
# project containing repo hooks.
643643
self.enabled_repo_hooks = []
644644

645-
# This will be updated later if the project has submodules and
646-
# if they will be synced.
647-
self.has_subprojects = False
648-
649645
def RelPath(self, local=True):
650646
"""Return the path for the project relative to a manifest.
651647
@@ -1563,8 +1559,8 @@ def fail(error: Exception):
15631559
# TODO(https://git-scm.com/docs/git-worktree#_bugs): Re-evaluate if
15641560
# submodules can be init when using worktrees once its support is
15651561
# complete.
1566-
if self.has_subprojects and not self.use_git_worktrees:
1567-
self._InitSubmodules()
1562+
if self.parent and not self.use_git_worktrees:
1563+
self._InitSubmodule()
15681564
all_refs = self.bare_ref.all
15691565
self.CleanPublishedCache(all_refs)
15701566
revid = self.GetRevisionId(all_refs)
@@ -2359,8 +2355,6 @@ def GetDerivedSubprojects(self):
23592355
)
23602356
result.append(subproject)
23612357
result.extend(subproject.GetDerivedSubprojects())
2362-
if result:
2363-
self.has_subprojects = True
23642358
return result
23652359

23662360
def EnableRepositoryExtension(self, key, value="true", version=1):
@@ -3030,16 +3024,39 @@ def _SyncSubmodules(self, quiet=True):
30303024
project=self.name,
30313025
)
30323026

3033-
def _InitSubmodules(self, quiet=True):
3034-
"""Initialize the submodules for the project."""
3027+
def _InitSubmodule(self, quiet=True):
3028+
"""Initialize the submodule."""
30353029
cmd = ["submodule", "init"]
30363030
if quiet:
30373031
cmd.append("-q")
3038-
if GitCommand(self, cmd).Wait() != 0:
3039-
raise GitError(
3040-
f"{self.name} submodule init",
3041-
project=self.name,
3032+
cmd.extend(["--", self.worktree])
3033+
max_retries = 3
3034+
base_delay_secs = 1
3035+
jitter_ratio = 1 / 3
3036+
for attempt in range(max_retries):
3037+
git_cmd = GitCommand(
3038+
None,
3039+
cmd,
3040+
cwd=self.parent.worktree,
3041+
capture_stdout=True,
3042+
capture_stderr=True,
30423043
)
3044+
if git_cmd.Wait() == 0:
3045+
return
3046+
error = git_cmd.stderr or git_cmd.stdout
3047+
if "lock" in error:
3048+
delay = base_delay_secs * (2**attempt)
3049+
delay += random.uniform(0, delay * jitter_ratio)
3050+
logger.warning(
3051+
f"Attempt {attempt+1}/{max_retries}: "
3052+
+ f"git {' '.join(cmd)} failed."
3053+
+ f" Error: {error}."
3054+
+ f" Sleeping {delay:.2f}s before retrying."
3055+
)
3056+
time.sleep(delay)
3057+
else:
3058+
break
3059+
git_cmd.VerifyCommand()
30433060

30443061
def _Rebase(self, upstream, onto=None):
30453062
cmd = ["rebase"]

0 commit comments

Comments
 (0)