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

Re: [RFC/PATCH 0/3] protocol v2

From
Shawn Pearce <spearce@spearce.org>
Date
Mar 4, 2015, 19:10 UTC
Message-ID
<CAJo=hJupr=07+r6z5s9RiT_v2LYtdioiVS=yNfMag+mKfH9FhA@mail.gmail.com>
In-Reply-To
<CACsJy8B=MN412dZYYc=NwpXHVz=Pxv+8wWMT7JNurVgqKrWn8A@mail.gmail.com>
On Wed, Mar 4, 2015 at 4:05 AM, Duy Nguyen <pclouds@gmail.com> wrote:
Show 11 quoted lines
> On Wed, Mar 4, 2015 at 11:27 AM, Shawn Pearce <spearce@spearce.org> wrote:
>> Let me go on a different tangent a bit from the current protocol.
>>
>> http://www.grpc.io/ was recently released and is built on the HTTP/2
>> standard. It uses protobuf as a proven extensibility mechanism.
>> Including a full C based grpc stack just to speak the Git wire
>> protocol is quite likely overkill, but I think the embedding of a
>> proven extensible format inside of a bi-directional framed streaming
>> system like HTTP/2 offers some good guidance.
>
> I'll take this as "learn from grpc, not just reuse grpc"
Correct, that was what I was trying to say and I just wrote it poorly.

HTTP 1.x, HTTP/2 and protobuf have proven themselves to be fairly open to extension and working well in the wild for transports. There is useful guidance there that we should draw from to try and leave doors open for the future.

HTTP/2, protobuf and grpc are fairly complex. I consider any one of them too complicated for Git specific use. However HTTP/2 is probably the future of HTTP stacks so we may see it show up in libcurl or something as popular as libcurl in another 10 years. Hg had some reasonably sane ideas about building the wire protocol to work well on HTTP 1.x upfront rather than Git tacking it on much later.

Show 15 quoted lines
>> Network protocol parsing is hard. Especially in languages like C where
>> buffer overflows are possible. Or where a client could trivially DoS a
>> server by sending a packet of size uint_max and the server naively
>> trying to malloc() that buffer. Defining the network protocol in an
>> IDL like protobuf 3 and being machine generated from stable well
>> maintained code has its advantages.
>
> I'm still studying the spec, so I can't comment if using IDL/protobuf3
> is a good idea yet.
>
> But I think at least we can avoid DoS by changing the pkt-line (again)
> a bit: the length 0xffff means that actual length is 0xfffe and the
> next pkt-line is part of this pkt-line. Higher level (upload-pack or
> fetch-pack, for example) must set an upper limit for packet_read() so
> it won't try to concatenate pkt-lines forever.

pkt-line is a reasonably simple and efficient framing system. A 64 KiB pkt-line frame only costs ~0.0061% overhead; ~0.0076% overhead if you are a pack stream in a side-band-64k channel. That is probably more efficient than HTTP/2 or SSL framing.

I see no reason to attempt to try and reduce that overhead further. 64 KiB frame size is enough for anyone to move data efficiently with these headers. In practice you are going to wrap that up into SSH or SSL/TLS and those overheads are so much higher it doesn't matter we have a tiny loss here.

I think a mistake in the wire protocol was making the pkt-line length human readable hex, but the sideband channel binary. _If_ we redo the framing the only change I would make is making the side band readable. Thus far we have only used 0, 1, 2 for sideband channels. These could easily be moved into human readable channel ids:

  'd':  currently sideband 0; this is the application data, aka the pack data
  'p':  currently sideband 1; this is the progress stream for stderr
  'e':  currently sideband 2; there was an error, data in this packet
is the message text, and the connection will shutdown after the
packet.

And then leave all other sideband values undefined and reserved for future use, just like they are all open today.

I am not convinced framing changes are necessary. I would fine with leaving the sideband streams as 0,1,2... but if we want a text based protocol for ease of debugging we should be text based across the board and try very hard to avoid these binary values in the framing, or ever needing to use a magical NUL byte in the middle of a packet to find a gap in older parsers for newer data.

If you want to build a larger stream like ref advertisement inside a pkt-line framing without using a pkt-line per ref record, you should follow the approach used by pack data streams where it uses the 5 byte side-band pkt-line framing and a side-band channel is allocated for that data. Application code can then run a side-band demux to yank out the inner stream and parse it.

It may be simpler to restrict ref names to be smaller than 64k in length so you have room for framing and hash value to be transferred inside of a single pkt-line, then use the pkt-line framing to do the transfer.

Today's upload-pack ref advertisment has ~25% overhead. Most of that is in the duplicated tag name for the peeled refs/tags/v1.0^{} lines. If you drop those names (but keep the pkt-line and SHA-1), its only about 8% overhead above the packed-refs file.

I think optimization efforts for ref advertisement need to focus on reducing the number of refs sent back and forth, not shrinking the individual records down smaller.

Earlier in this thread Junio raised a point that the flush-pkt is confusing because it has way too many purposes. I agree. IIRC we have 0001-0003 as invalid pkt-line headers that could be used for special markers in the stream.

For example we could use 0000 flush-pkt as "end of section" and define 0001 as "i am done speaking and now wait for you to reply".

I think we need to keep 0004 as "empty packet" in case we ever get ourselves into a position where it makes sense to pass an empty string from one end of the connection to another.

Running pkt-line inside of side-band-64k is... weird to read. IIRC we only do that in the smart HTTP protocol to the remote-curl helper, and this is where Junio's remarks about flush-pkt being confusing come from. If we rewrote the protocol to have that explicit 0001 "i am done talking" marker the helper wouldn't need the double framing to understand how to break up the originally bidirectional packet stream into a sequence of bursts sent on unidirectional HTTP 1.x.

Previous: Duy NguyenNext: Stefan Beller
Message 47 of 80 in “protocol v2”
  1. 0/3 protocol v2Stefan Beller, Feb 24, 2015
  2. 1/3 Document protocol capabilities extensionStefan Beller, Feb 24, 2015
  3. 2/3 receive-pack: add advertisement of different protocol optionsStefan Beller, Feb 24, 2015
  4. 3/3 receive-pack: enable protocol v2Stefan Beller, Feb 24, 2015
  5. Duy NguyenFeb 24, 2015
  6. Stefan BellerFeb 24, 2015
  7. Junio C HamanoFeb 24, 2015
  8. Stefan BellerFeb 24, 2015
  9. Duy NguyenFeb 25, 2015
  10. Junio C HamanoFeb 25, 2015
  11. Stefan BellerFeb 26, 2015
  12. Duy NguyenFeb 26, 2015
  13. Stefan BellerFeb 26, 2015
  14. Junio C HamanoFeb 26, 2015
  15. Stefan BellerFeb 27, 2015
  16. Stefan BellerFeb 27, 2015
  17. Junio C HamanoFeb 27, 2015
  18. Stefan BellerFeb 27, 2015
  19. Junio C HamanoFeb 28, 2015
  20. Stefan BellerFeb 28, 2015
  21. 0/5 protocol v2 for upload-packStefan Beller, Feb 28, 2015
  22. 1/5 upload-pack: only accept capabilities on the first "want" lineStefan Beller, Feb 28, 2015
  23. 2/5 upload-pack: support out of band client capability requestsStefan Beller, Feb 28, 2015
  24. Kyle J. McKayFeb 28, 2015
  25. Duy NguyenFeb 28, 2015
  26. Kyle J. McKayFeb 28, 2015
  27. Duy NguyenMar 1, 2015
  28. Duy NguyenFeb 28, 2015
  29. 3/5 connect.c: connect to a remote service with some flagsStefan Beller, Feb 28, 2015
  30. Torsten BögershausenFeb 28, 2015
  31. Junio C HamanoMar 1, 2015
  32. 4/5 daemon.c: accept extra service argumentsStefan Beller, Feb 28, 2015
  33. Junio C HamanoMar 1, 2015
  34. 5/5 WIP/Document the http protocol changeStefan Beller, Feb 28, 2015
  35. Duy NguyenFeb 28, 2015
  36. Johannes SixtMar 1, 2015
  37. Junio C HamanoMar 2, 2015
  38. Junio C HamanoMar 2, 2015
  39. Duy NguyenMar 2, 2015
  40. Duy NguyenMar 2, 2015
  41. Duy NguyenMar 3, 2015
  42. Junio C HamanoMar 3, 2015
  43. Junio C HamanoMar 3, 2015
  44. Duy NguyenMar 4, 2015
  45. Shawn PearceMar 4, 2015
  46. Duy NguyenMar 4, 2015
  47. Shawn PearceMar 4, 2015
  48. Stefan BellerMar 5, 2015
  49. Stefan BellerMar 5, 2015
  50. Stefan BellerMar 24, 2015
  51. Junio C HamanoMar 24, 2015
  52. protocol upload-pack-v2Stefan Beller, Mar 6, 2015
  53. Stefan BellerMar 6, 2015
  54. Duy NguyenMar 6, 2015
  55. Duy NguyenMar 7, 2015
  56. Junio C HamanoMar 7, 2015
  57. Stefan BellerMar 7, 2015
  58. Duy NguyenMar 7, 2015
  59. Junio C HamanoMar 8, 2015
  60. Junio C HamanoMar 31, 2015
  61. Duy NguyenApr 2, 2015
  62. Junio C HamanoApr 2, 2015
  63. Martin FickApr 2, 2015
  64. Junio C HamanoApr 2, 2015
  65. Stefan BellerApr 2, 2015
  66. Stefan BellerApr 2, 2015
  67. Duy NguyenMar 10, 2015
  68. Kyle J. McKayMar 10, 2015
  69. Duy NguyenFeb 28, 2015
  70. Junio C HamanoFeb 28, 2015
  71. Junio C HamanoMar 1, 2015
  72. Duy NguyenMar 1, 2015
  73. Stefan BellerMar 1, 2015
  74. David LangMar 2, 2015
  75. Junio C HamanoMar 1, 2015
  76. David LangMar 2, 2015
  77. Junio C HamanoMar 2, 2015
  78. Philip OakleyMar 1, 2015
  79. Duy NguyenMar 2, 2015
  80. Stefan BellerFeb 27, 2015

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.