Re: [PATCH 1/1] commit-graph: fix writing first commit-graph during fetch

2019-10-22 Thread Jeff King
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

2019-10-22 Thread Jeff King
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

2019-10-22 Thread Derrick Stolee



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

2019-10-22 Thread SZEDER Gábor
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

2019-10-22 Thread Jeff King
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

2019-10-22 Thread Jeff King
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