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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: client/internal/logdog/butler/bundler/sizer.go
diff --git a/client/internal/logdog/butler/bundler/sizer.go b/client/internal/logdog/butler/bundler/sizer.go
new file mode 100644
index 0000000000000000000000000000000000000000..e28c73e634b90f6c07ffbedd639ac747e25f25fd
--- /dev/null
+++ b/client/internal/logdog/butler/bundler/sizer.go
@@ -0,0 +1,120 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package bundler
+
+import (
+ "errors"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+
+ "github.com/golang/protobuf/proto"
+ "github.com/luci/luci-go/common/logdog/protocol"
+)
+
+var (
+ sizeOfBundleEntryTag int
+ sizeOfLogEntryTag int
+ sizeOfTerminalTag int
+ sizeOfTerminalIndexTag int
+
+ errMalformedProtobufField = errors.New("malformed protobuf field")
+)
+
+const (
+ // sizeOfBoolTrue is the size of the "true" boolean value.
+ sizeOfBoolTrue = 1
+)
+
+func init() {
+ b := &protocol.ButlerLogBundle{}
+ sizeOfBundleEntryTag = mustCalculateTagSize(b, "Entries")
+
+ be := &protocol.ButlerLogBundle_Entry{}
+ sizeOfLogEntryTag = mustCalculateTagSize(be, "Logs")
+ sizeOfTerminalTag = mustCalculateTagSize(be, "Terminal")
+ sizeOfTerminalIndexTag = mustCalculateTagSize(be, "TerminalIndex")
+}
+
+func mustCalculateTagSize(i interface{}, field string) int {
+ value, err := calculateTagSize(i, field)
+ if err != nil {
+ panic(err)
+ }
+ return value
+}
+
+func protoSize(m proto.Message) int {
+ return proto.Size(m)
+}
+
+func calculateTagSize(i interface{}, field string) (int, error) {
+ v := reflect.TypeOf(i)
+ if v.Kind() == reflect.Ptr {
+ v = v.Elem()
+ }
+ if v.Kind() != reflect.Struct {
+ return 0, fmt.Errorf("sizer: %s is not a struct", v)
+ }
+
+ f, ok := v.FieldByName(field)
+ if !ok {
+ return 0, fmt.Errorf("sizer: could not find field %s.%s", v, field)
+ }
+
+ tag, err := protobufTag(f)
+ if err != nil {
+ return 0, fmt.Errorf("sizer: field %s.%s has no protobuf tag: %s", v, field, err)
+ }
+
+ // Protobuf encodes the tag and wire type in the same varint. It does this
+ // by allocating three bits for wire type at the base of the tag.
+ //
+ // https://developers.google.com/protocol-buffers/docs/encoding#structure
+ return varintLength(uint64(tag) << 3), nil
+}
+
+func varintLength(val uint64) int {
+ switch {
+ case val == 0:
+ return 0
+ case val < 0x80:
+ return 1
+ case val < 0x4000:
+ return 2
+ case val < 0x200000:
+ return 3
+ case val < 0x10000000:
+ return 4
+ case val < 0x800000000:
+ return 5
+ case val < 0x40000000000:
+ return 6
+ case val < 0x2000000000000:
+ return 7
+ case val < 0x100000000000000:
+ return 8
+ case val < 0x8000000000000000:
+ return 9
+ default:
+ // Maximum uvarint size.
+ return 10
+ }
+}
+
+func protobufTag(f reflect.StructField) (int, error) {
+ // If this field doesn't have a "protobuf" tag, ignore it.
+ value := f.Tag.Get("protobuf")
+ parts := strings.Split(value, ",")
+ if len(parts) < 2 {
+ return 0, errMalformedProtobufField
+ }
+ tag, err := strconv.Atoi(parts[1])
+ if err != nil {
+ return 0, errMalformedProtobufField
+ }
+ return tag, nil
+}
« 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