File: batch.go

package info (click to toggle)
golang-golang-x-exp 0.0~git20250911.df92998-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,284 kB
  • sloc: ansic: 1,900; objc: 276; sh: 270; asm: 48; makefile: 27
file content (124 lines) | stat: -rw-r--r-- 3,601 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Code generated by "gen.bash" from internal/trace; DO NOT EDIT.

//go:build go1.23

package trace

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"

	"golang.org/x/exp/trace/internal/tracev2"
	"golang.org/x/exp/trace/internal/version"
)

// timestamp is an unprocessed timestamp.
type timestamp uint64

// batch represents a batch of trace events.
// It is unparsed except for its header.
type batch struct {
	m    ThreadID
	time timestamp
	data []byte
	exp  tracev2.Experiment
}

func (b *batch) isStringsBatch() bool {
	return b.exp == tracev2.NoExperiment && len(b.data) > 0 && tracev2.EventType(b.data[0]) == tracev2.EvStrings
}

func (b *batch) isStacksBatch() bool {
	return b.exp == tracev2.NoExperiment && len(b.data) > 0 && tracev2.EventType(b.data[0]) == tracev2.EvStacks
}

func (b *batch) isCPUSamplesBatch() bool {
	return b.exp == tracev2.NoExperiment && len(b.data) > 0 && tracev2.EventType(b.data[0]) == tracev2.EvCPUSamples
}

func (b *batch) isSyncBatch(ver version.Version) bool {
	return (b.exp == tracev2.NoExperiment && len(b.data) > 0) &&
		((tracev2.EventType(b.data[0]) == tracev2.EvFrequency && ver < version.Go125) ||
			(tracev2.EventType(b.data[0]) == tracev2.EvSync && ver >= version.Go125))
}

func (b *batch) isEndOfGeneration() bool {
	return b.exp == tracev2.NoExperiment && len(b.data) > 0 && tracev2.EventType(b.data[0]) == tracev2.EvEndOfGeneration
}

// readBatch reads the next full batch from r.
func readBatch(r interface {
	io.Reader
	io.ByteReader
}) (batch, uint64, error) {
	// Read batch header byte.
	b, err := r.ReadByte()
	if err != nil {
		return batch{}, 0, err
	}
	if typ := tracev2.EventType(b); typ == tracev2.EvEndOfGeneration {
		return batch{m: NoThread, exp: tracev2.NoExperiment, data: []byte{b}}, 0, nil
	}
	if typ := tracev2.EventType(b); typ != tracev2.EvEventBatch && typ != tracev2.EvExperimentalBatch {
		return batch{}, 0, fmt.Errorf("expected batch event, got event %d", typ)
	}

	// Read the experiment of we have one.
	exp := tracev2.NoExperiment
	if tracev2.EventType(b) == tracev2.EvExperimentalBatch {
		e, err := r.ReadByte()
		if err != nil {
			return batch{}, 0, err
		}
		exp = tracev2.Experiment(e)
	}

	// Read the batch header: gen (generation), thread (M) ID, base timestamp
	// for the batch.
	gen, err := binary.ReadUvarint(r)
	if err != nil {
		return batch{}, gen, fmt.Errorf("error reading batch gen: %w", err)
	}
	m, err := binary.ReadUvarint(r)
	if err != nil {
		return batch{}, gen, fmt.Errorf("error reading batch M ID: %w", err)
	}
	ts, err := binary.ReadUvarint(r)
	if err != nil {
		return batch{}, gen, fmt.Errorf("error reading batch timestamp: %w", err)
	}

	// Read in the size of the batch to follow.
	size, err := binary.ReadUvarint(r)
	if err != nil {
		return batch{}, gen, fmt.Errorf("error reading batch size: %w", err)
	}
	if size > tracev2.MaxBatchSize {
		return batch{}, gen, fmt.Errorf("invalid batch size %d, maximum is %d", size, tracev2.MaxBatchSize)
	}

	// Copy out the batch for later processing.
	var data bytes.Buffer
	data.Grow(int(size))
	n, err := io.CopyN(&data, r, int64(size))
	if n != int64(size) {
		return batch{}, gen, fmt.Errorf("failed to read full batch: read %d but wanted %d", n, size)
	}
	if err != nil {
		return batch{}, gen, fmt.Errorf("copying batch data: %w", err)
	}

	// Return the batch.
	return batch{
		m:    ThreadID(m),
		time: timestamp(ts),
		data: data.Bytes(),
		exp:  exp,
	}, gen, nil
}