This patch fixes the following issue: When we found the commit in the graph in lookup_commit_in_graph(), but the commit is missing from the repository, we will try promisor_remote_get_direct() and then enter another loop. Then we will go into an endless loop: git fetch -> deref_without_lazy_fetch() -> lookup_commit_in_graph() -> repo_has_object_file() -> promisor_remote_get_direct() -> fetch_objects() -> git fetch (a new loop round) Changes since v2: * Remove test_have_prereq() from ULIMIT_PROCESSES as "run_with_limited_processses true" is enough. * Teach run_with_limited_processses() to support dash and zsh. * Skip the whole test file if ulimit is not avaliable. * Minor grammar/comment etc. fixes throughout. Han Xin (2): test-lib.sh: add limited processes to test-lib commit-graph.c: no lazy fetch in lookup_commit_in_graph() commit-graph.c | 2 +- t/t5329-no-lazy-fetch-with-commit-graph.sh | 53 ++++++++++++++++++++++ t/test-lib.sh | 16 +++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100755 t/t5329-no-lazy-fetch-with-commit-graph.sh Range-diff against v2: 1: 442a4c351d ! 1: ad0a539759 test-lib.sh: add limited processes to test-lib @@ t/test-lib.sh: test_lazy_prereq ULIMIT_FILE_DESCRIPTORS ' ' +run_with_limited_processses () { -+ (ulimit -u 512 && "$@") ++ # bash and ksh use "ulimit -u", dash uses "ulimit -p" ++ if test -n "$BASH_VERSION" ++ then ++ ulimit_max_process="-u" ++ elif test -n "$KSH_VERSION" ++ then ++ ulimit_max_process="-u" ++ fi ++ (ulimit ${ulimit_max_process-"-p"} 512 && "$@") +} + +test_lazy_prereq ULIMIT_PROCESSES ' -+ test_have_prereq !HPPA,!MINGW,!CYGWIN && + run_with_limited_processses true +' + 2: a7d456db9b ! 2: 3cdb1abd43 commit-graph.c: no lazy fetch in lookup_commit_in_graph() @@ Metadata ## Commit message ## commit-graph.c: no lazy fetch in lookup_commit_in_graph() - If a commit is in the commit graph, we would expect the commit to also - be present. So we should use has_object() instead of - repo_has_object_file(), which will help us avoid getting into an endless - loop of lazy fetch. + The commit-graph is used to opportunistically optimize accesses to + certain pieces of information on commit objects, and + lookup_commit_in_graph() tries to say "no" when the requested commit + does not locally exist by returning NULL, in which case the caller + can ask for (which may result in on-demand fetching from a promisor + remote) and parse the commit object itself. - When we found the commit in the graph in lookup_commit_in_graph(), but - the commit is missing from the repository, we will try - promisor_remote_get_direct() and then enter another loop. While - sometimes it will finally succeed because it cannot fork subprocess, - it has exhausted the local process resources and can be harmful to the - remote service. + However, it uses a wrong helper, repo_has_object_file(), to do so. + This helper not only checks if an object is mmediately available in + the local object store, but also tries to fetch from a promisor remote. + But the fetch machinery calls lookup_commit_in_graph(), thus causing an + infinite loop. + + We should make lookup_commit_in_graph() expect that a commit given to it + can be legitimately missing from the local object store, by using the + has_object_file() helper instead. Signed-off-by: Han Xin <hanxin.hx@xxxxxxxxxxxxx> @@ t/t5329-no-lazy-fetch-with-commit-graph.sh (new) + +. ./test-lib.sh + ++if ! test_have_prereq ULIMIT_PROCESSES ++then ++ skip_all='skipping tests for no lazy fetch with the commit-graph, ulimit processes not available' ++ test_done ++fi ++ +test_expect_success 'setup: prepare a repository with a commit' ' + git init with-commit && + test_commit -C with-commit the-commit && @@ t/t5329-no-lazy-fetch-with-commit-graph.sh (new) + # create a ref that points to the commit in alternates + git -C with-commit-graph update-ref refs/ref_to_the_commit "$oid" && + # prepare some other objects to commit-graph -+ test_commit -C with-commit-graph somthing && ++ test_commit -C with-commit-graph something && + git -c gc.writeCommitGraph=true -C with-commit-graph gc && + test_path_is_file with-commit-graph/.git/objects/info/commit-graph +' @@ t/t5329-no-lazy-fetch-with-commit-graph.sh (new) + test_must_fail git -C with-commit-graph cat-file -e $oid +' + -+test_expect_success 'setup: prepare another commit to fetch' ' -+ test_commit -C with-commit another-commit && ++test_expect_success 'setup: prepare any commit to fetch' ' ++ test_commit -C with-commit any-commit && + anycommit=$(git -C with-commit rev-parse HEAD) +' + -+test_expect_success ULIMIT_PROCESSES 'fetch any commit from promisor with the usage of the commit graph' ' ++test_expect_success 'fetch any commit from promisor with the usage of the commit graph' ' + git -C with-commit-graph remote add origin "$(pwd)/with-commit" && + git -C with-commit-graph config remote.origin.promisor true && + git -C with-commit-graph config remote.origin.partialclonefilter blob:none && -- 2.36.1