github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/internal/trace/v2/batch.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package trace 6 7 import ( 8 "bytes" 9 "encoding/binary" 10 "fmt" 11 "io" 12 13 "internal/trace/v2/event" 14 "internal/trace/v2/event/go122" 15 ) 16 17 // timestamp is an unprocessed timestamp. 18 type timestamp uint64 19 20 // batch represents a batch of trace events. 21 // It is unparsed except for its header. 22 type batch struct { 23 m ThreadID 24 time timestamp 25 data []byte 26 } 27 28 func (b *batch) isStringsBatch() bool { 29 return len(b.data) > 0 && event.Type(b.data[0]) == go122.EvStrings 30 } 31 32 func (b *batch) isStacksBatch() bool { 33 return len(b.data) > 0 && event.Type(b.data[0]) == go122.EvStacks 34 } 35 36 func (b *batch) isCPUSamplesBatch() bool { 37 return len(b.data) > 0 && event.Type(b.data[0]) == go122.EvCPUSamples 38 } 39 40 func (b *batch) isFreqBatch() bool { 41 return len(b.data) > 0 && event.Type(b.data[0]) == go122.EvFrequency 42 } 43 44 // readBatch reads the next full batch from r. 45 func readBatch(r interface { 46 io.Reader 47 io.ByteReader 48 }) (batch, uint64, error) { 49 // Read batch header byte. 50 b, err := r.ReadByte() 51 if err != nil { 52 return batch{}, 0, err 53 } 54 if typ := event.Type(b); typ != go122.EvEventBatch { 55 return batch{}, 0, fmt.Errorf("expected batch event (%s), got %s", go122.EventString(go122.EvEventBatch), go122.EventString(typ)) 56 } 57 58 // Read the batch header: gen (generation), thread (M) ID, base timestamp 59 // for the batch. 60 gen, err := binary.ReadUvarint(r) 61 if err != nil { 62 return batch{}, gen, fmt.Errorf("error reading batch gen: %w", err) 63 } 64 m, err := binary.ReadUvarint(r) 65 if err != nil { 66 return batch{}, gen, fmt.Errorf("error reading batch M ID: %w", err) 67 } 68 ts, err := binary.ReadUvarint(r) 69 if err != nil { 70 return batch{}, gen, fmt.Errorf("error reading batch timestamp: %w", err) 71 } 72 73 // Read in the size of the batch to follow. 74 size, err := binary.ReadUvarint(r) 75 if err != nil { 76 return batch{}, gen, fmt.Errorf("error reading batch size: %w", err) 77 } 78 if size > go122.MaxBatchSize { 79 return batch{}, gen, fmt.Errorf("invalid batch size %d, maximum is %d", size, go122.MaxBatchSize) 80 } 81 82 // Copy out the batch for later processing. 83 var data bytes.Buffer 84 data.Grow(int(size)) 85 n, err := io.CopyN(&data, r, int64(size)) 86 if n != int64(size) { 87 return batch{}, gen, fmt.Errorf("failed to read full batch: read %d but wanted %d", n, size) 88 } 89 if err != nil { 90 return batch{}, gen, fmt.Errorf("copying batch data: %w", err) 91 } 92 93 // Return the batch. 94 return batch{ 95 m: ThreadID(m), 96 time: timestamp(ts), 97 data: data.Bytes(), 98 }, gen, nil 99 }