1
2
3
4
5 package counter
6
7 import (
8 "bytes"
9 "fmt"
10 "strings"
11 "unsafe"
12
13 "golang.org/x/telemetry/internal/mmap"
14 )
15
16 type File struct {
17 Meta map[string]string
18 Count map[string]uint64
19 }
20
21 func Parse(filename string, data []byte) (*File, error) {
22 if !bytes.HasPrefix(data, []byte(hdrPrefix)) || len(data) < pageSize {
23 if len(data) < pageSize {
24 return nil, fmt.Errorf("%s: file too short (%d<%d)", filename, len(data), pageSize)
25 }
26 return nil, fmt.Errorf("%s: wrong hdr (not %q)", filename, hdrPrefix)
27 }
28 corrupt := func() (*File, error) {
29
30 return nil, fmt.Errorf("%s: corrupt counter file", filename)
31 }
32
33 f := &File{
34 Meta: make(map[string]string),
35 Count: make(map[string]uint64),
36 }
37 np := round(len(hdrPrefix), 4)
38 hdrLen := *(*uint32)(unsafe.Pointer(&data[np]))
39 if hdrLen > pageSize {
40 return corrupt()
41 }
42 meta := data[np+4 : hdrLen]
43 if i := bytes.IndexByte(meta, 0); i >= 0 {
44 meta = meta[:i]
45 }
46 m := &mappedFile{
47 meta: string(meta),
48 hdrLen: hdrLen,
49 mapping: &mmap.Data{Data: data},
50 }
51
52 lines := strings.Split(m.meta, "\n")
53 for _, line := range lines {
54 if line == "" {
55 continue
56 }
57 k, v, ok := strings.Cut(line, ": ")
58 if !ok {
59 return corrupt()
60 }
61 f.Meta[k] = v
62 }
63
64 for i := uint32(0); i < numHash; i++ {
65 headOff := hdrLen + hashOff + i*4
66 head := m.load32(headOff)
67 off := head
68 for off != 0 {
69 ename, next, v, ok := m.entryAt(off)
70 if !ok {
71 return corrupt()
72 }
73 if _, ok := f.Count[string(ename)]; ok {
74 return corrupt()
75 }
76 ctrName := DecodeStack(string(ename))
77 f.Count[ctrName] = v.Load()
78 off = next
79 }
80 }
81 return f, nil
82 }
83
View as plain text