Simplify remote-helper transport after review · Entire
Simplify remote-helper transport after review
c4495b4→main·
Soph·4w ago·3 files·+87 added/-67 removed
Post-review cleanup of the remote-helper transport, no behavior change:
- Extract a shared readRawPktLine primitive in pktline.go and route both readAdvertisement and responseEndReader through it, replacing two hand-rolled copies of pkt-line header parsing. This also adds the pktline.MaxSize bound both copies were missing, and lets responseEndReader reuse one grow-only buffer instead of allocating per packet — relaying a multi-GB pack now costs no per-packet allocation.
- Drop the unreachable os.ErrClosed guard in helperProcess.finish (the sync.Once already makes a redundant close impossible) and collapse it to a single errors.Join.
- Merge RequestInfoRefs's twin error branches into one errors.Join.
- Fold newConn's scheme dispatch into a single switch so the native scheme set is named once instead of split between a switch and a trailing if.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Sessions
de61fb4754bbView transcript
[?
❯ GITSYNC_MAX_REF_UPDATES_PER_PUSH=5000 go run ./cmd/git-sync replicate --all-refs --stats --verbose \Claude Code·Opus 4.8[1m]·5 steps](/content/gh/entireio/git-sync/session/4f8f5e9b-9f90-4c22-88b9-988c55f45833#timeline-de61fb4754bb/index.html)
Changes
3
internal
gitproto
Mhelper.go+28/-59
Mpktline.go+48
syncer
Msyncer.go+11/-8
42 unmodified lines
43
44
45
46
47
48
49
50
51
52
53
54
44 unmodified lines
99
100
101
96
97
98
99
100
101
102
103
104
105
106
107
108
89 unmodified lines
198
199
200
197
198
201
202
203
204
205
31 unmodified lines
237
238
239
236
237
238
239
240
240
241
242
243
9 unmodified lines
253
254
255
256
256
257
258
258
259
260
261
261
262
263
262
263
264
265
265
266
266
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
267
268
269
1 unmodified line
271
272
273
290
274
275
276
277
293
278
279
280
281
282
16 unmodified lines
299
300
301
316
317
302
303
304
305
320
321
306
307
308
324
325
326
309
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
310
311
312
313
314
42 unmodified lines
// no native transport for (e.g. entire://) by delegating auth and the actual
// network I/O to the helper, while still running the wire protocol itself.
//
// It assumes the helper supports stateless-connect (the modern v2 bridge) for
// both upload-pack and receive-pack — it issues stateless-connect directly
// rather than negotiating via the capabilities handshake, and treats a
// "fallback" reply as an error. git-remote-entire satisfies this; a helper that
// only offers the legacy `connect` capability is not supported.
//
// Each Conn operation spawns its own helper process and tears it down when the
// operation completes. This is deliberate, not lazy: the helper services
// exactly one stateless-connect session per process (its protocol loop returns
44 unmodified lines
return nil, err
}
adv, readErr := readAdvertisement(proc.out)
finishErr := proc.finish()
if readErr != nil {
return nil, fmt.Errorf("%s advertisement: %w", service, errors.Join(readErr, finishErr))
}
if finishErr != nil {
return nil, fmt.Errorf("%s advertisement: %w", service, finishErr)
// errors.Join drops nils, so this covers the readErr-only, finishErr-only,
// and both-set cases in one branch.
if err := errors.Join(readErr, proc.finish()); err != nil {
return nil, fmt.Errorf("%s advertisement: %w", service, err)
}
return adv, nil
}
// readAck consumes the helper's stateless-connect response line: an empty line // means the connection is established, "fallback" means it can't speak the // smart protocol, and anything else is an error (with captured stderr). // means the connection is established, "fallback" means it can't proxy this // service, and anything else is an error (with captured stderr). func (p *helperProcess) readAck() error { line, err := p.out.ReadString('\n') if err != nil { 31 unmodified lines
func (p *helperProcess) finish() error { closeErr := p.closeStdin() _, _ = io.Copy(io.Discard, p.out) //nolint:errcheck // best-effort drain before Wait; exit status is authoritative waitErr := p.wait() if closeErr != nil && !errors.Is(closeErr, os.ErrClosed) { return errors.Join(closeErr, waitErr) } return waitErr return errors.Join(closeErr, p.wait()) } // cleanup force-tears-down the process on an error path. 9 unmodified lines
// it as the section terminator. func readAdvertisement(br *bufio.Reader) ([]byte, error) { var buf bytes.Buffer var header [4]byte var scratch []byte for { if _, err := io.ReadFull(br, header[:]); err != nil { kind, frame, err := readRawPktLine(br, scratch) if err != nil { return nil, fmt.Errorf("read advertisement pkt-line: %w", err) } buf.Write(header[:]) switch string(header[:]) { case "0000": buf.Write(frame) scratch = frame // reuse the (possibly grown) backing buffer next iteration if kind == PacketFlush { return buf.Bytes(), nil } case "0001", "0002": continue } n, err := parseHexLength(header) if err != nil { return nil, fmt.Errorf("advertisement pkt-line: %w", err) } if n < 4 { return nil, fmt.Errorf("advertisement pkt-line: invalid length %d", n) } if n == 4 { continue } payload := make([]byte, n-4) if _, err := io.ReadFull(br, payload); err != nil { return nil, fmt.Errorf("read advertisement payload: %w", err) } buf.Write(payload) } } }
1 unmodified line
// io.EOF when it reaches the stateless-connect response-end (0002) packet. The // 0002 is consumed but never forwarded, so the downstream protocol parser sees // exactly the same bytes it would from an HTTP response body (which ends at the // connection's EOF instead). // connection's EOF instead). The frame buffer is reused across packets, so // relaying a multi-GB pack costs no per-packet allocation. type responseEndReader struct { src *bufio.Reader pending []byte buf []byte // reused backing for the current frame pending []byte // unread bytes of the current frame (sub-slice of buf) done bool }
16 unmodified lines
}
func (r *responseEndReader) fill() error { var header [4]byte if _, err := io.ReadFull(r.src, header[:]); err != nil { kind, frame, err := readRawPktLine(r.src, r.buf) if err != nil { return fmt.Errorf("read response pkt-line: %w", err) } switch string(header[:]) { case "0002": if kind == PacketResponseEnd { r.done = true return io.EOF } case "0000", "0001": r.pending = append([]byte(nil), header[:]...) return nil } n, err := parseHexLength(header) if err != nil { return fmt.Errorf("response pkt-line: %w", err) } if n < 4 { return fmt.Errorf("response pkt-line: invalid length %d", n) } buf := make([]byte, n) copy(buf, header[:]) if n > 4 { if _, err := io.ReadFull(r.src, buf[4:]); err != nil { return fmt.Errorf("read response payload: %w", err) } } r.pending = buf r.buf = frame // retain the grown backing for the next fill r.pending = frame return nil } }
Minternal/gitproto/helper.go+28/-59
79 unmodified lines
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
79 unmodified lines
return PacketData, pr.buf, nil }
// readRawPktLine reads one pkt-line and returns its type plus the verbatim // on-wire bytes — the 4-byte length header followed by any payload — so callers // that must relay or accumulate the exact wire framing (unlike ReadPacket, // which yields only the payload) can do so. scratch is reused as backing // storage and grown as needed; pass the slice returned by the previous call to // avoid per-packet allocation. The returned slice aliases scratch and is valid // only until the next call. func readRawPktLine(br *bufio.Reader, scratch []byte) (PacketType, []byte, error) { if cap(scratch) < 4 { scratch = make([]byte, 4) } frame := scratch[:4] if _, err := io.ReadFull(br, frame); err != nil { return PacketData, nil, fmt.Errorf("read pktline header: %w", err) } switch string(frame) { case "0000": return PacketFlush, frame, nil case "0001": return PacketDelim, frame, nil case "0002": return PacketResponseEnd, frame, nil }
var header [4]byte copy(header[:], frame) n, err := parseHexLength(header) if err != nil { return PacketData, nil, err } if n < 4 || n > pktline.MaxSize { return PacketData, nil, pktline.ErrInvalidPktLen } if n > cap(scratch) { grown := make([]byte, n) copy(grown, frame) scratch = grown } else { scratch = scratch[:n] } if n > 4 { if _, err := io.ReadFull(br, scratch[4:n]); err != nil { return PacketData, nil, fmt.Errorf("read pktline payload: %w", err) } } return PacketData, scratch[:n], nil }
func parseHexLength(header [4]byte) (int, error) { var n int for _, b := range header {