git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 2/2] receive-pack: use advertised reference tips to inform connectivity check

From
Taylor Blau <me@ttaylorr.com>
Date
Nov 1, 2022, 01:28 UTC
Message-ID
<Y2B2KeYX5X9vp+cf@nand.local>
In-Reply-To
<Y1/fm1prlAs3U1NE@ncase>
On Mon, Oct 31, 2022 at 03:45:47PM +0100, Patrick Steinhardt wrote:
Show 33 quoted lines
> On Sun, Oct 30, 2022 at 03:09:04PM -0400, Taylor Blau wrote:
> > On Fri, Oct 28, 2022 at 04:42:27PM +0200, Patrick Steinhardt wrote:
> > > This strategy has the major downside that it will not require any object
> > > to be sent by the client that is reachable by any of the repositories'
> > > references. While that sounds like it would be indeed what we are after
> > > with the connectivity check, it is arguably not. The administrator that
> > > manages the server-side Git repository may have configured certain refs
> > > to be hidden during the reference advertisement via `transfer.hideRefs`
> > > or `receivepack.hideRefs`. Whatever the reason, the result is that the
> > > client shouldn't expect that any of those hidden references exists on
> > > the remote side, and neither should they assume any of the pointed-to
> > > objects to exist except if referenced by any visible reference. But
> > > because we treat _all_ local refs as uninteresting in the connectivity
> > > check, a client is free to send a packfile that references objects that
> > > are only reachable via a hidden reference on the server-side, and we
> > > will gladly accept it.
> >
> > You mention below that this is a correctness issue, but I am not sure
> > that I agree.
> >
> > The existing behavior is a little strange, I agree, but your argument
> > relies on an assumption that the history on hidden refs is not part of
> > the reachable set, which is not the case. Any part of the repository
> > that is reachable from _any_ reference, hidden or not, is reachable by
> > definition.
> >
> > So it's perfectly fine to consider objects on hidden refs to be in the
> > uninteresting set, because they are reachable. It's odd from the
> > client's perspective, but I do not see a path to repository corruption
> > with thee existing behavior.
>
> Indeed, I'm not trying to say that this can lead to repository
> corruption.

I definitely agree with that. I have thought about this on-and-off since you sent the topic, and I am pretty certain that there is no path to repository corruption with the existing behavior. It would be worth updating the commit message to make this clearer.

> But security-related or not, I think it is safe to say that any packfile
> sent by a client that does not contain objects required for the updated
> reference that the client cannot know to exist on the server-side must
> be generated by buggy code.

Maybe, though I think it's fine to let clients send us smaller packfiles if they have some a-priori knowledge that the server has objects that it isn't advertising. And that can all happen without buggy code. So it's weird, but there isn't anything wrong with letting it happen.

Show 28 quoted lines
> [snip]
> > Why do we see a slowdown when there there aren't any hidden references?
> > Or am I misunderstanding your patch message which instead means "we see
> > a slow-down when there are no hidden references [since we still must
> > store and enumerate all advertised references]"?
>
> I have tried to dig down into the code of `revision.c` but ultimately
> returned empty-handed. I _think_ that this is because of the different
> paths we use when reading revisions from stdin as we have to resolve the
> revision to an OID first, which is more involved than taking the OIDs as
> returned by the reference backend. I have tried to short-circuit this
> logic in case the revision read from stdin is exactly `hash_algo->hexsz`
> long so that we try to parse it as an OID directly instead of trying to
> do any of the magic that is required to resolve a revision. But this
> only speed things up by a small margin.
>
> Another assumption was that this is overhead caused by using stdin
> instead of reading data from a file, but flame graphs didn't support
> this theory, either.
>
> > If the latter, could we avoid invoking the new machinery altogether? In
> > other words, shouldn't receive-pack only set the reachable_oids_fn() to
> > enumerate advertised references only when the set of advertised
> > references differs from the behavior of `--not --all`?
>
> Yeah, I was taking a "wait for feedback and see" stance on this. We can
> easily make the logic conditional on whether there are any hidden refs
> at all.

Yeah, I think that this would be preferable. I'm surprised that your data doesn't support the idea that the slowdown is caused by reading from stdin instead of parsing `--not --all`. I'd be curious to see what you have tried so far.

I'm almost certain that forcing rev-list to chew through a bunch of data on stdin that is basically equivalent to saying `--not --all` is going to be the source of the slowdown.

Show 17 quoted lines
> > >  	if (check_connected(iterate_receive_command_list, &data, &opt))
> > >  		set_connectivity_errors(commands, si);
> > >
> > > @@ -2462,6 +2473,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
> > >  {
> > >  	int advertise_refs = 0;
> > >  	struct command *commands;
> > > +	struct oidset announced_oids = OIDSET_INIT;
> >
> > This looks like trading one problem for another. In your above example,
> > we now need to store 20 bytes of OIDs 6.8M times, or ~130 MiB. Not the
> > end of the world, but it feels like an avoidable problem.
>
> We store these references in an `oidset` before this patch set already,
> but yes, the lifetime is longer now. But note that this set stores the
> announced objects, not the hidden ones. So we don't store 6.8m OIDs, but
> only the 250k announced ones.

Hmm, OK. I wonder, could rev-list be given a `--refs=<namespace>` argument which is equal to the advertised references? Or something that implies "give me all of the references which aren't hidden?"

If we call that maybe `--visible-refs=receive` (to imply the references *not* in receive.hideRefs), then our connectivity check would become:

    git rev-list --stdin --not --visible-refs=receive

or something like that. Not having to extend the lifetime of these OIDs in an oidset would be worthwhile. Besides, having a new rev-list option is cool, too ;-).

Show 11 quoted lines
> > Could we enumerate the references in a callback to for_each_ref() and
> > only emit ones which aren't hidden? Storing these and then recalling
> > them after the fact is worth avoiding.
>
> Sorry, I don't quite get what you're proposing. `for_each_ref()` already
> does exactly that: it stores every reference that is not hidden in the
> above `oidset`. This is the exact set of advertised references, which in
> my example repository would be about 250k. This information is used by
> git-receive-pack(1) to avoid announcing the same object twice, and now
> it's also used to inform the connectivity check to use these objects as
> the set of already-reachable objects.
Yes, ignore me ;-).

Thanks, Taylor

Previous: Patrick SteinhardtNext: Patrick Steinhardt
Message 14 of 88 in “receive-pack: use advertised reference tips to inform connectivity check”
  1. 0/2 receive-pack: use advertised reference tips to inform connectivity checkPatrick Steinhardt, Oct 28, 2022
  2. 1/2 connected: allow supplying different view of reachable objectsPatrick Steinhardt, Oct 28, 2022
  3. Ævar Arnfjörð BjarmasonOct 28, 2022
  4. Junio C HamanoOct 28, 2022
  5. Taylor BlauOct 30, 2022
  6. Patrick SteinhardtOct 31, 2022
  7. Taylor BlauNov 1, 2022
  8. 2/2 receive-pack: use advertised reference tips to inform connectivity checkPatrick Steinhardt, Oct 28, 2022
  9. Ævar Arnfjörð BjarmasonOct 28, 2022
  10. Patrick SteinhardtOct 31, 2022
  11. Ævar Arnfjörð BjarmasonOct 31, 2022
  12. Taylor BlauOct 30, 2022
  13. Patrick SteinhardtOct 31, 2022
  14. Taylor BlauNov 1, 2022
  15. Patrick SteinhardtNov 1, 2022
  16. Patrick SteinhardtNov 1, 2022
  17. Taylor BlauNov 2, 2022
  18. Jeff KingNov 1, 2022
  19. Junio C HamanoOct 28, 2022
  20. Taylor BlauNov 1, 2022
  21. Jeff KingNov 1, 2022
  22. Patrick SteinhardtNov 1, 2022
  23. 0/3 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 3, 2022
  24. 1/3 refs: get rid of global list of hidden refsPatrick Steinhardt, Nov 3, 2022
  25. 2/3 revision: add new parameter to specify all visible refsPatrick Steinhardt, Nov 3, 2022
  26. Jeff KingNov 5, 2022
  27. Patrick SteinhardtNov 7, 2022
  28. Jeff KingNov 8, 2022
  29. Jeff KingNov 5, 2022
  30. 3/3 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 3, 2022
  31. Taylor BlauNov 5, 2022
  32. Jeff KingNov 5, 2022
  33. Jeff KingNov 5, 2022
  34. 0/6 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 7, 2022
  35. 2/6 revision: move together exclusion-related functionsPatrick Steinhardt, Nov 7, 2022
  36. 1/6 refs: get rid of global list of hidden refsPatrick Steinhardt, Nov 7, 2022
  37. 6/6 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 7, 2022
  38. 3/6 revision: introduce struct to handle exclusionsPatrick Steinhardt, Nov 7, 2022
  39. Ævar Arnfjörð BjarmasonNov 7, 2022
  40. Patrick SteinhardtNov 8, 2022
  41. 5/6 revparse: add `--exclude-hidden=` optionPatrick Steinhardt, Nov 7, 2022
  42. Jeff KingNov 8, 2022
  43. 4/6 revision: add new parameter to exclude hidden refsPatrick Steinhardt, Nov 7, 2022
  44. Ævar Arnfjörð BjarmasonNov 7, 2022
  45. Ævar Arnfjörð BjarmasonNov 7, 2022
  46. Patrick SteinhardtNov 8, 2022
  47. Patrick SteinhardtNov 8, 2022
  48. Taylor BlauNov 8, 2022
  49. Patrick SteinhardtNov 8, 2022
  50. Jeff KingNov 8, 2022
  51. Taylor BlauNov 8, 2022
  52. 0/6 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 8, 2022
  53. 1/6 refs: get rid of global list of hidden refsPatrick Steinhardt, Nov 8, 2022
  54. Ævar Arnfjörð BjarmasonNov 8, 2022
  55. Patrick SteinhardtNov 8, 2022
  56. Jeff KingNov 8, 2022
  57. 2/6 revision: move together exclusion-related functionsPatrick Steinhardt, Nov 8, 2022
  58. 5/6 rev-parse: add `--exclude-hidden=` optionPatrick Steinhardt, Nov 8, 2022
  59. 3/6 revision: introduce struct to handle exclusionsPatrick Steinhardt, Nov 8, 2022
  60. 4/6 revision: add new parameter to exclude hidden refsPatrick Steinhardt, Nov 8, 2022
  61. Jeff KingNov 8, 2022
  62. Taylor BlauNov 8, 2022
  63. Patrick SteinhardtNov 11, 2022
  64. 6/6 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 8, 2022
  65. 0/7 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 11, 2022
  66. 1/7 refs: fix memory leak when parsing hideRefs configPatrick Steinhardt, Nov 11, 2022
  67. 2/7 refs: get rid of global list of hidden refsPatrick Steinhardt, Nov 11, 2022
  68. 3/7 revision: move together exclusion-related functionsPatrick Steinhardt, Nov 11, 2022
  69. 4/7 revision: introduce struct to handle exclusionsPatrick Steinhardt, Nov 11, 2022
  70. 5/7 revision: add new parameter to exclude hidden refsPatrick Steinhardt, Nov 11, 2022
  71. 6/7 rev-parse: add `--exclude-hidden=` optionPatrick Steinhardt, Nov 11, 2022
  72. 7/7 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 11, 2022
  73. Taylor BlauNov 11, 2022
  74. Jeff KingNov 15, 2022
  75. Taylor BlauNov 16, 2022
  76. Jeff KingNov 16, 2022
  77. Taylor BlauNov 16, 2022
  78. Patrick SteinhardtNov 17, 2022
  79. 0/7 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 17, 2022
  80. 1/7 refs: fix memory leak when parsing hideRefs configPatrick Steinhardt, Nov 17, 2022
  81. 2/7 refs: get rid of global list of hidden refsPatrick Steinhardt, Nov 17, 2022
  82. 3/7 revision: move together exclusion-related functionsPatrick Steinhardt, Nov 17, 2022
  83. 4/7 revision: introduce struct to handle exclusionsPatrick Steinhardt, Nov 17, 2022
  84. 5/7 revision: add new parameter to exclude hidden refsPatrick Steinhardt, Nov 17, 2022
  85. 6/7 rev-parse: add `--exclude-hidden=` optionPatrick Steinhardt, Nov 17, 2022
  86. 7/7 receive-pack: only use visible refs for connectivity checkPatrick Steinhardt, Nov 17, 2022
  87. Jeff KingNov 17, 2022
  88. Taylor BlauNov 17, 2022

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.