src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

parse.go (1813B)


      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 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 		// TODO(rfindley): return a useful error message.
     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 }