Skip to content

Commit 65e81f0

Browse files
[mq] [skip ddci] working branch - merge 9034d27 on top of main at b65de16
{"baseBranch":"main","baseCommit":"b65de168bd2b5bb47f4f361a207dfb410b50a1b8","createdAt":"2026-07-02T11:19:24.699118Z","headSha":"9034d27a3e61ad5bd94632b058378580024e2b68","id":"917b4059-b5da-4fd9-9d3c-cf23429affc9","priority":"200","pullRequestNumber":"4960","queuedAt":"2026-07-02T11:19:24.698001Z","status":"STATUS_QUEUED"}
2 parents 9c831f1 + 9034d27 commit 65e81f0

3 files changed

Lines changed: 43 additions & 23 deletions

File tree

ddtrace/tracer/option.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,32 @@ func (t *dummyTransport) endpoint() string {
13721372
return "http://localhost:9/v1.0/traces"
13731373
}
13741374

1375+
// discardTransport drains and discards trace payloads without decoding them.
1376+
// It reads the whole body like a real HTTP send would (so encoded-buffer
1377+
// lifetime and flush timing stay realistic) but never returns decoded
1378+
// spans.
1379+
// To use over dummyTransport in benchmarks that measure span creation/encoding
1380+
// and doesn't care for decoding overhead that a customer app never performs.
1381+
type discardTransport struct{}
1382+
1383+
var _ ddTransport = discardTransport{}
1384+
1385+
func (discardTransport) send(p payload) (io.ReadCloser, error) {
1386+
defer p.Close()
1387+
if _, err := io.Copy(io.Discard, p); err != nil {
1388+
return nil, err
1389+
}
1390+
return io.NopCloser(strings.NewReader("OK")), nil
1391+
}
1392+
1393+
func (discardTransport) sendStats(*pb.ClientStatsPayload, int) error {
1394+
return nil
1395+
}
1396+
1397+
func (discardTransport) endpoint() string {
1398+
return "http://localhost:9/v1.0/traces"
1399+
}
1400+
13751401
func decode(p payloadReader) (spanLists, []uint64, error) {
13761402
br := bufio.NewReader(p)
13771403
head, err := br.Peek(1)
@@ -1401,12 +1427,11 @@ func decode(p payloadReader) (spanLists, []uint64, error) {
14011427
}
14021428
return traces, ids, nil
14031429
case first == msgpackMap16 || first == msgpackMap32 || first&0xf0 == msgpackMapFix:
1404-
buf, err := io.ReadAll(br)
1405-
if err != nil {
1430+
payload := newPayloadV1()
1431+
payload.buf = make([]byte, 0, p.size())
1432+
if _, err := io.Copy(payload, br); err != nil {
14061433
return nil, nil, err
14071434
}
1408-
payload := newPayloadV1()
1409-
payload.buf = buf
14101435
if _, err := payload.decodeBuffer(); err != nil {
14111436
return nil, nil, err
14121437
}

ddtrace/tracer/tracer_test.go

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2455,13 +2455,14 @@ func BenchmarkPartialFlushing(b *testing.B) {
24552455
}
24562456

24572457
func BenchmarkPartialFlushingSpanPool(b *testing.B) {
2458+
addr := mockAgentEndpoint(b, "/v1.0/traces")
24582459
b.Run("Enabled", func(b *testing.B) {
24592460
b.Setenv("DD_TRACE_PARTIAL_FLUSH_ENABLED", "true")
24602461
b.Setenv("DD_TRACE_PARTIAL_FLUSH_MIN_SPANS", "500")
2461-
genBigTraces(b, WithSpanPool(true))
2462+
genBigTraces(b, WithAgentAddr(addr.Host), WithSpanPool(true))
24622463
})
24632464
b.Run("Disabled", func(b *testing.B) {
2464-
genBigTraces(b, WithSpanPool(true))
2465+
genBigTraces(b, WithAgentAddr(addr.Host), WithSpanPool(true))
24652466
})
24662467
}
24672468

@@ -2473,7 +2474,8 @@ func BenchmarkBigTraces(b *testing.B) {
24732474
}
24742475

24752476
func genBigTraces(b *testing.B, opts ...StartOption) {
2476-
tracer, transport, flush, stop, err := startTestTracer(b, append(opts, WithLogger(log.DiscardLogger{}))...)
2477+
opts = append(opts, withTransport(discardTransport{}))
2478+
tracer, _, flush, stop, err := startTestTracer(b, append(opts, WithLogger(log.DiscardLogger{}))...)
24772479
assert.Nil(b, err)
24782480
defer stop()
24792481

@@ -2510,20 +2512,14 @@ func genBigTraces(b *testing.B, opts ...StartOption) {
25102512
sp.Finish()
25112513
}
25122514
parent.Finish()
2513-
// TODO(fg): This test has historically not waited for the two
2514-
// goroutines below to finish. This was causing test failures when
2515+
// TODO(fg): This test has historically not waited for the flush
2516+
// goroutine below to finish. This was causing test failures when
25152517
// goroutine leak checks were added to TestMain. However, looking at
25162518
// the code, perhaps these goroutines should be required to finish
25172519
// before b.StopTimer() is called?
2518-
wg.Add(2)
2519-
go func() {
2520+
wg.Go(func() {
25202521
flush(-1) // act like a ticker
2521-
wg.Done()
2522-
}()
2523-
go func() {
2524-
transport.Reset() // pretend we sent any payloads
2525-
wg.Done()
2526-
}()
2522+
})
25272523
}
25282524
}
25292525
b.StopTimer()

ddtrace/tracer/tracertest_test.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,12 @@ func (a *testAgent) handleTracesV04(w http.ResponseWriter, r *http.Request) {
136136
}
137137

138138
func (a *testAgent) handleTracesV1(w http.ResponseWriter, r *http.Request) {
139-
body, err := io.ReadAll(r.Body)
140-
if err != nil {
141-
http.Error(w, err.Error(), http.StatusBadRequest)
142-
return
143-
}
139+
// Copy the body directly into the payload buffer rather than buffering the
140+
// whole request with io.ReadAll first: payloadV1.Write appends to p.buf,
141+
// which decodeBuffer consumes in place, so a separate full-body slice would
142+
// just be an extra copy.
144143
p := newPayloadV1()
145-
if _, err := p.Write(body); err != nil {
144+
if _, err := io.Copy(p, r.Body); err != nil {
146145
http.Error(w, err.Error(), http.StatusBadRequest)
147146
return
148147
}

0 commit comments

Comments
 (0)