Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(166)

Side by Side Diff: client/internal/logdog/butler/bundler/sizer.go

Issue 1412063008: logdog: Add bundler library. (Closed) Base URL: https://github.com/luci/luci-go@logdog-review-streamserver
Patch Set: Updated from comments. Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package bundler
6
7 import (
8 "errors"
9 "fmt"
10 "reflect"
11 "strconv"
12 "strings"
13
14 "github.com/golang/protobuf/proto"
15 "github.com/luci/luci-go/common/logdog/protocol"
16 )
17
18 var (
19 sizeOfBundleEntryTag int
20 sizeOfLogEntryTag int
21 sizeOfTerminalTag int
22 sizeOfTerminalIndexTag int
23
24 errMalformedProtobufField = errors.New("malformed protobuf field")
25 )
26
27 const (
28 // sizeOfBoolTrue is the size of the "true" boolean value.
29 sizeOfBoolTrue = 1
30 )
31
32 func init() {
33 b := &protocol.ButlerLogBundle{}
34 sizeOfBundleEntryTag = mustCalculateTagSize(b, "Entries")
35
36 be := &protocol.ButlerLogBundle_Entry{}
37 sizeOfLogEntryTag = mustCalculateTagSize(be, "Logs")
38 sizeOfTerminalTag = mustCalculateTagSize(be, "Terminal")
39 sizeOfTerminalIndexTag = mustCalculateTagSize(be, "TerminalIndex")
40 }
41
42 func mustCalculateTagSize(i interface{}, field string) int {
43 value, err := calculateTagSize(i, field)
44 if err != nil {
45 panic(err)
46 }
47 return value
48 }
49
50 func protoSize(m proto.Message) int {
51 return proto.Size(m)
52 }
53
54 func calculateTagSize(i interface{}, field string) (int, error) {
55 v := reflect.TypeOf(i)
56 if v.Kind() == reflect.Ptr {
57 v = v.Elem()
58 }
59 if v.Kind() != reflect.Struct {
60 return 0, fmt.Errorf("sizer: %s is not a struct", v)
61 }
62
63 f, ok := v.FieldByName(field)
64 if !ok {
65 return 0, fmt.Errorf("sizer: could not find field %s.%s", v, fie ld)
66 }
67
68 tag, err := protobufTag(f)
69 if err != nil {
70 return 0, fmt.Errorf("sizer: field %s.%s has no protobuf tag: %s ", v, field, err)
71 }
72
73 // Protobuf encodes the tag and wire type in the same varint. It does th is
74 // by allocating three bits for wire type at the base of the tag.
75 //
76 // https://developers.google.com/protocol-buffers/docs/encoding#structur e
77 return varintLength(uint64(tag) << 3), nil
78 }
79
80 func varintLength(val uint64) int {
81 switch {
82 case val == 0:
83 return 0
84 case val < 0x80:
85 return 1
86 case val < 0x4000:
87 return 2
88 case val < 0x200000:
89 return 3
90 case val < 0x10000000:
91 return 4
92 case val < 0x800000000:
93 return 5
94 case val < 0x40000000000:
95 return 6
96 case val < 0x2000000000000:
97 return 7
98 case val < 0x100000000000000:
99 return 8
100 case val < 0x8000000000000000:
101 return 9
102 default:
103 // Maximum uvarint size.
104 return 10
105 }
106 }
107
108 func protobufTag(f reflect.StructField) (int, error) {
109 // If this field doesn't have a "protobuf" tag, ignore it.
110 value := f.Tag.Get("protobuf")
111 parts := strings.Split(value, ",")
112 if len(parts) < 2 {
113 return 0, errMalformedProtobufField
114 }
115 tag, err := strconv.Atoi(parts[1])
116 if err != nil {
117 return 0, errMalformedProtobufField
118 }
119 return tag, nil
120 }
OLDNEW
« no previous file with comments | « client/internal/logdog/butler/bundler/parser_test.go ('k') | client/internal/logdog/butler/bundler/sizer_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698