Re: [PATCH 1/1] commit-graph: fix writing first commit-graph during fetch
On Tue, Oct 22, 2019 at 08:48:20PM -0400, Jeff King wrote: > I admit I am puzzled, though, _why_ the presence of the submodule > matters. That is, from your explanation, I thought the issue was simply > that `fetch` walked (and marked) some commits, and the flags overlapped > with what the commit-graph code expected. > > I could guess that the presence of the submodule triggers some analysis > for --recurse-submodules. But then we don't actually recurse (maybe > because they're not activated? In which case maybe we shouldn't be doing > that extra walk to look for submodules if there aren't any activated > ones in our local repo). Indeed, that seems to be it. If I do this: git init repo cd repo cat >.gitmodules <<\EOF [submodule "foo"] path = foo url = https://example.com EOF time git fetch /path/to/git.git then we end up traversing the whole git.git history a second time, even though we should know off the bat that there are no active submodules that we would recurse to. Doing this makes the problem go away: diff --git a/submodule.c b/submodule.c index 0f199c5137..0db2f18b93 100644 --- a/submodule.c +++ b/submodule.c @@ -1193,7 +1193,7 @@ static void calculate_changed_submodule_paths(struct repository *r, struct string_list_item *name; /* No need to check if there are no submodules configured */ - if (!submodule_from_path(r, NULL, NULL)) + if (!is_submodule_active(r, NULL)) return; argv_array_push(&argv, "--"); /* argv[0] program name */ but causes some tests to fail (I think that in some cases we're supposed to auto-initialize, and we'd probably need to cover that case, too). All of this is outside of your fix, of course, but: 1. I'm satisfied now that I understand why the test triggers the problem. 2. You may want have a real activated submodule in your test. Right now we'll trigger the submodule-recursion check even without that, but in the future we might do something like the hunk above. In which case your test wouldn't be checking anything interesting anymore. -Peff
Re: [PATCH 1/1] commit-graph: fix writing first commit-graph during fetch
On Tue, Oct 22, 2019 at 08:35:57PM -0400, Derrick Stolee wrote: > > In the cover letter Derrick mentioned that he used > > https://github.com/derrickstolee/numbers for testing, and that repo > > has a submodule as well. > > I completely forgot that I put a submodule in that repo. It makes sense > that the Git repo also has one. Thanks for the test! I'll get it into > the test suite tomorrow. Ah, right. Good catch Gábor. The test below fails for me without your patch, and succeeds with it (the extra empty commit is necessary so that we have a parent). I admit I am puzzled, though, _why_ the presence of the submodule matters. That is, from your explanation, I thought the issue was simply that `fetch` walked (and marked) some commits, and the flags overlapped with what the commit-graph code expected. I could guess that the presence of the submodule triggers some analysis for --recurse-submodules. But then we don't actually recurse (maybe because they're not activated? In which case maybe we shouldn't be doing that extra walk to look for submodules if there aren't any activated ones in our local repo). I'd also wonder if it would be possible to trigger in another way (say, due to want/have negotiation, though I guess most of the walking there is done on the server side). But it may not be worth digging too far into it. -Peff --- diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index ecabbe1616..1b092fec0b 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -583,6 +583,21 @@ test_expect_success 'fetch.writeCommitGraph' ' ) ' +test_expect_success 'fetch.writeCommitGraph with a submodule' ' + git init has-submodule && + ( + cd has-submodule && + git commit --allow-empty -m parent && + git submodule add ../three && + git commit -m "add submodule" + ) && + git clone has-submodule submod-clone && + ( + cd submod-clone && + git -c fetch.writeCommitGraph fetch origin + ) +' + # configured prune tests set_config_tristate () {
Re: [PATCH 1/1] commit-graph: fix writing first commit-graph during fetch
On 10/22/2019 7:35 PM, SZEDER Gábor wrote: > On Tue, Oct 22, 2019 at 05:45:54PM -0400, Jeff King wrote: >> Puzzling... > > Submodules? > > $ cd ~/src/git/ > $ git quotelog 86cfd61e6b > 86cfd61e6b (sha1dc: optionally use sha1collisiondetection as a submodule, > 2017-07-01) > $ git init --bare good.git > Initialized empty Git repository in /home/szeder/src/git/good.git/ > $ git push -q good.git 86cfd61e6b^:refs/heads/master > $ git clone good.git good-clone > Cloning into 'good-clone'... > done. > $ git -c fetch.writeCommitGraph -C good-clone fetch origin > Computing commit graph generation numbers: 100% (46958/46958), done. > $ git init --bare bad.git > Initialized empty Git repository in /home/szeder/src/git/bad.git/ > $ git push -q bad.git 86cfd61e6b:refs/heads/master > $ git clone bad.git bad-clone > Cloning into 'bad-clone'... > done. > $ git -c fetch.writeCommitGraph -C bad-clone fetch origin > Computing commit graph generation numbers: 100% (1/1), done. > BUG: commit-graph.c:886: missing parent > 9936c1b52a39fa14fca04f937df3e75f7498ac66 for commit > 86cfd61e6bc12745751c43b4f69886b290cd85cb > Aborted > > In the cover letter Derrick mentioned that he used > https://github.com/derrickstolee/numbers for testing, and that repo > has a submodule as well. I completely forgot that I put a submodule in that repo. It makes sense that the Git repo also has one. Thanks for the test! I'll get it into the test suite tomorrow. -Stolee
Re: [PATCH 1/1] commit-graph: fix writing first commit-graph during fetch
On Tue, Oct 22, 2019 at 05:45:54PM -0400, Jeff King wrote: > On Tue, Oct 22, 2019 at 04:33:16PM -0400, Jeff King wrote: > > > > I have failed to produce a test using the file:// protocol that > > > demonstrates this bug. > > > > Hmm, from the description, it sounds like it should be easy. I might > > poke at it a bit. > > Hmph. I can reproduce it here, but it seems to depend on the repository. > If I do this: > > diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh > index ecabbe1616..8d473a456f 100755 > --- a/t/t5510-fetch.sh > +++ b/t/t5510-fetch.sh > @@ -583,6 +583,14 @@ test_expect_success 'fetch.writeCommitGraph' ' > ) > ' > > +test_expect_success 'fetch.writeCommitGraph with a bigger repo' ' > + git clone "$TEST_DIRECTORY/.." repo && > + ( > + cd repo && > + git -c fetch.writeCommitGraph fetch origin > + ) > +' > + > # configured prune tests > > set_config_tristate () { > > it reliably triggers the bug. But if I make a synthetic repo, even it > has a lot of commits (thousands or more), it doesn't trigger. I thought > maybe it had to do with having commits that were not at tips (since the > tip ones presumably _are_ fed into the graph generation process). But > that doesn't seem to help. > > Puzzling... Submodules? $ cd ~/src/git/ $ git quotelog 86cfd61e6b 86cfd61e6b (sha1dc: optionally use sha1collisiondetection as a submodule, 2017-07-01) $ git init --bare good.git Initialized empty Git repository in /home/szeder/src/git/good.git/ $ git push -q good.git 86cfd61e6b^:refs/heads/master $ git clone good.git good-clone Cloning into 'good-clone'... done. $ git -c fetch.writeCommitGraph -C good-clone fetch origin Computing commit graph generation numbers: 100% (46958/46958), done. $ git init --bare bad.git Initialized empty Git repository in /home/szeder/src/git/bad.git/ $ git push -q bad.git 86cfd61e6b:refs/heads/master $ git clone bad.git bad-clone Cloning into 'bad-clone'... done. $ git -c fetch.writeCommitGraph -C bad-clone fetch origin Computing commit graph generation numbers: 100% (1/1), done. BUG: commit-graph.c:886: missing parent 9936c1b52a39fa14fca04f937df3e75f7498ac66 for commit 86cfd61e6bc12745751c43b4f69886b290cd85cb Aborted In the cover letter Derrick mentioned that he used https://github.com/derrickstolee/numbers for testing, and that repo has a submodule as well.
Re: [PATCH 1/1] commit-graph: fix writing first commit-graph during fetch
On Tue, Oct 22, 2019 at 04:33:16PM -0400, Jeff King wrote: > > I have failed to produce a test using the file:// protocol that > > demonstrates this bug. > > Hmm, from the description, it sounds like it should be easy. I might > poke at it a bit. Hmph. I can reproduce it here, but it seems to depend on the repository. If I do this: diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index ecabbe1616..8d473a456f 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -583,6 +583,14 @@ test_expect_success 'fetch.writeCommitGraph' ' ) ' +test_expect_success 'fetch.writeCommitGraph with a bigger repo' ' + git clone "$TEST_DIRECTORY/.." repo && + ( + cd repo && + git -c fetch.writeCommitGraph fetch origin + ) +' + # configured prune tests set_config_tristate () { it reliably triggers the bug. But if I make a synthetic repo, even it has a lot of commits (thousands or more), it doesn't trigger. I thought maybe it had to do with having commits that were not at tips (since the tip ones presumably _are_ fed into the graph generation process). But that doesn't seem to help. Puzzling... -Peff
Re: [PATCH 1/1] commit-graph: fix writing first commit-graph during fetch
On Tue, Oct 22, 2019 at 05:28:55PM +, Derrick Stolee via GitGitGadget wrote: > However, the UNINTERESTING flag is used in lots of places in the > codebase. This flag usually means some barrier to stop a commit walk, > such as in revision-walking to compare histories. It is not often > cleared after the walk completes because the starting points of those > walks do not have the UNINTERESTING flag, and clear_commit_marks() would > stop immediately. Oof. Nicely explained, and your fix makes sense. The global-ness of revision flags always makes me nervous about doing more things in-process (this isn't the first such bug we've had). I have a dream of converting most uses of flags into using a commit-slab. That provides cheap access to an auxiliary structure, so each traversal, etc, could keep its own flag structure. I'm not sure if it would have a performance impact, though. Even though it's O(1), it is an indirect lookup, which could have some memory-access impact (though my guess is it would be lost in the noise). One of the sticking points is that all object types, not just commits, use flags. But we only assign slab ids to commits. I noticed recently that "struct object" has quite a few spare bits in it these days, because the switch to a 32-byte oid means 64-bit machines now have an extra 4 bytes of padding. I wonder if we could use that to store an index field. Anyway, that's getting far off the topic; clearly we need a fix in the meantime, and what you have here looks good to me. > I tested running clear_commit_marks_many() to clear the UNINTERESTING > flag inside close_reachable(), but the tips did not have the flag, so > that did nothing. Another option would be clear_object_flags(), which just walks all of the in-memory structs. Your REACHABLE solution is cheaper, though. > Instead, I finally arrived on the conclusion that I should use a flag > that is not used in any other part of the code. In commit-reach.c, a > number of flags were defined for commit walk algorithms. The REACHABLE > flag seemed like it made the most sense, and it seems it was not > actually used in the file. Yeah, being able to remove it from commit-reach.c surprised me for a moment. To further add to the confusion, builtin/fsck.c has its own REACHABLE flag (with a different bit and a totally different purpose). I don't think there's any practical problem there, though. > I have failed to produce a test using the file:// protocol that > demonstrates this bug. Hmm, from the description, it sounds like it should be easy. I might poke at it a bit. -Peff