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

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

Issue 1276923003: logdog: Add bundler library. (Closed) Base URL: https://github.com/luci/luci-go@logdog-review-streamserver
Patch Set: Created 5 years, 4 months 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 "fmt"
9 "reflect"
10 "strconv"
11 "strings"
12
13 "github.com/golang/protobuf/proto"
14 "github.com/luci/luci-go/common/logdog/protocol"
15 "github.com/luci/luci-go/common/logdog/protocol/protoutil"
16 "github.com/luci/luci-go/common/logdog/types"
17 )
18
19 var (
20 bundleEntryTagSize int
21 logEntryTagSize int
22 )
23
24 func init() {
25 bundleEntryTagSize = mustCalculateTagSize(&protocol.ButlerLogBundle{}, " Entries")
26 logEntryTagSize = mustCalculateTagSize(&protocol.ButlerLogBundle_Entry{} , "Logs")
27 }
28
29 func mustCalculateTagSize(i interface{}, field string) int {
30 value, err := calculateTagSize(i, field)
31 if err != nil {
32 panic(err)
33 }
34 return value
35 }
36
37 func calculateTagSize(i interface{}, field string) (int, error) {
38 v := reflect.TypeOf(i)
39 if v.Kind() == reflect.Ptr {
40 v = v.Elem()
41 }
42 if v.Kind() != reflect.Struct {
43 return 0, fmt.Errorf("sizer: %s is not a struct", v)
44 }
45
46 f, ok := v.FieldByName(field)
47 if !ok {
48 return 0, fmt.Errorf("sizer: could not find field %s.%s", v, fie ld)
49 }
50
51 tag := protobufTag(f)
52 if tag == -1 {
53 return 0, fmt.Errorf("sizer: field %s.%s has no protobuf tag", v , field)
54 }
55
56 return varintLength(uint64(tag) << 3), nil
tandrii(chromium) 2015/08/11 14:06:08 I guess that's how protobuf encodes stuff. Still w
dnj (Google) 2015/08/11 16:24:01 Done.
57 }
58
59 func varintLength(val uint64) int {
60 switch {
61 case val < 0x80:
62 return 1
63 case val < 0x4000:
64 return 2
65 case val < 0x200000:
66 return 3
67 case val < 0x10000000:
68 return 4
69 case val < 0x800000000:
70 return 5
71 case val < 0x40000000000:
72 return 6
73 case val < 0x2000000000000:
74 return 7
75 case val < 0x100000000000000:
76 return 8
77 case val < 0x8000000000000000:
78 return 9
79 default:
80 // Maximum uvarint size.
81 return 10
82 }
83 }
84
85 func protobufTag(f reflect.StructField) int {
86 // If this field doesn't have a "protobuf" tag, ignore it.
87 value := f.Tag.Get("protobuf")
88 parts := strings.Split(value, ",")
89 if len(parts) < 2 {
90 return -1
tandrii(chromium) 2015/08/11 14:06:08 Special return values => who are you, a C programm
dnj (Google) 2015/08/11 16:24:01 Done.
91 }
92 tag, err := strconv.Atoi(parts[1])
93 if err != nil {
94 return -1
95 }
96 return tag
97 }
98
99 type fastSizer struct {
100 size int
101
102 // As we add LogEntry to a ButlerLogBundle_Entry, the bundle entry's siz e (and
103 // therefore it's protobuf size prefix) will grow. We account for the gr owth
104 // by tracking the size of each ButlerLogBundle_Entry and updating it wh en
105 // we add a LogEntry to it. This is stored independently from the cumula tive
106 // size and factored in when Size() is calculated.
107 beSize map[types.StreamPath]int
108 }
109
110 // NewFastSizer is a Sizer that is optimized for LogDog protobufs.
tandrii(chromium) 2015/08/11 14:06:08 nit: i prefer to put public stuff at the top
dnj (Google) 2015/08/11 16:24:01 Done.
111 //
112 // In exchange for rapid size calculation, it performs worst-case estimates on
113 // the unknown protocol overheads, leading to potential size overestimation.
114 func NewFastSizer(b *protocol.ButlerLogBundle) Sizer {
115 return &fastSizer{
116 size: proto.Size(b),
117 beSize: make(map[types.StreamPath]int),
118 }
119 }
120
121 func (b *fastSizer) Size() int {
122 size := b.size
123 for _, v := range b.beSize {
124 size += varintLength(uint64(v))
125 }
126 return size
127 }
128
129 func (b *fastSizer) AppendBundleEntry(e *protocol.ButlerLogBundle_Entry) {
130 ps := proto.Size(e)
131 s := bundleEntryTagSize + ps
132 b.size += s
133 b.addBundleEntrySize(e, s)
134 }
135
136 func (b *fastSizer) AppendLogEntry(be *protocol.ButlerLogBundle_Entry, e *protoc ol.LogEntry) {
137 ps := proto.Size(e)
138 s := logEntryTagSize + varintLength(uint64(ps)) + ps
139 b.size += s
140 b.addBundleEntrySize(be, s)
141 }
142
143 func (b *fastSizer) addBundleEntrySize(e *protocol.ButlerLogBundle_Entry, count int) {
144 path := protoutil.DescriptorPath(e.GetDesc())
145 b.beSize[path] += count
146 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698