| OLD | NEW |
| (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 "sort" |
| 10 |
| 11 "github.com/luci/luci-go/common/logdog/protocol" |
| 12 ) |
| 13 |
| 14 // builder incrementally constructs ButlerLogBundle entries. |
| 15 type builder struct { |
| 16 // template is the base bundle template. |
| 17 template protocol.ButlerLogBundle |
| 18 // size is the maximum permitted bundle size. |
| 19 size int |
| 20 |
| 21 // templateCachedSize is the cached size of the ButlerLogBundle template
. |
| 22 templateCachedSize int |
| 23 // entries is the set of ButlerLogBundle_Entry stream state. |
| 24 beMap map[string]*protocol.ButlerLogBundle_Entry |
| 25 // beSizes tracks the size of a ButlerLogBundle_Entry. |
| 26 beSizes map[string]int |
| 27 } |
| 28 |
| 29 func (b *builder) remaining() int { |
| 30 return b.size - b.bundleSize() |
| 31 } |
| 32 |
| 33 func (b *builder) ready() bool { |
| 34 // Have we reached our desired size? |
| 35 return b.hasContent() && (b.bundleSize() >= b.size) |
| 36 } |
| 37 |
| 38 func (b *builder) bundleSize() int { |
| 39 if b.templateCachedSize == 0 { |
| 40 b.templateCachedSize = protoSize(&b.template) |
| 41 } |
| 42 |
| 43 size := b.templateCachedSize |
| 44 for _, sz := range b.beSizes { |
| 45 size += sizeOfBundleEntryTag + varintLength(uint64(sz)) + sz |
| 46 } |
| 47 |
| 48 return size |
| 49 } |
| 50 |
| 51 func (b *builder) hasContent() bool { |
| 52 return len(b.beMap) > 0 |
| 53 } |
| 54 |
| 55 func (b *builder) add(template *protocol.ButlerLogBundle_Entry, le *protocol.Log
Entry) { |
| 56 be := b.getCreateBundleEntry(template) |
| 57 |
| 58 be.Logs = append(be.Logs, le) |
| 59 psize := protoSize(le) |
| 60 |
| 61 // Pay the cost of the additional LogEntry. |
| 62 b.beSizes[template.Desc.Name] += sizeOfLogEntryTag + varintLength(uint64
(psize)) + psize |
| 63 } |
| 64 |
| 65 func (b *builder) setStreamTerminal(template *protocol.ButlerLogBundle_Entry, ti
dx uint64) { |
| 66 be := b.getCreateBundleEntry(template) |
| 67 if be.Terminal { |
| 68 if be.TerminalIndex != tidx { |
| 69 panic(fmt.Errorf("attempt to change terminal index %d =>
%d", be.TerminalIndex, tidx)) |
| 70 } |
| 71 return |
| 72 } |
| 73 |
| 74 be.Terminal = true |
| 75 be.TerminalIndex = tidx |
| 76 |
| 77 // Pay the cost of the additional terminal fields. |
| 78 b.beSizes[template.Desc.Name] += (sizeOfTerminalTag + sizeOfBoolTrue + |
| 79 sizeOfTerminalIndexTag + varintLength(be.TerminalIndex)) |
| 80 } |
| 81 |
| 82 func (b *builder) bundle() *protocol.ButlerLogBundle { |
| 83 bundle := b.template |
| 84 |
| 85 names := make([]string, 0, len(b.beMap)) |
| 86 for k := range b.beMap { |
| 87 names = append(names, k) |
| 88 } |
| 89 sort.Strings(names) |
| 90 |
| 91 bundle.Entries = make([]*protocol.ButlerLogBundle_Entry, len(names)) |
| 92 for idx, name := range names { |
| 93 bundle.Entries[idx] = b.beMap[name] |
| 94 } |
| 95 |
| 96 return &bundle |
| 97 } |
| 98 |
| 99 func (b *builder) getCreateBundleEntry(template *protocol.ButlerLogBundle_Entry)
*protocol.ButlerLogBundle_Entry { |
| 100 if be := b.beMap[template.Desc.Name]; be != nil { |
| 101 return be |
| 102 } |
| 103 |
| 104 // Initialize our maps (first time only). |
| 105 if b.beMap == nil { |
| 106 b.beMap = map[string]*protocol.ButlerLogBundle_Entry{} |
| 107 b.beSizes = map[string]int{} |
| 108 } |
| 109 |
| 110 templateCopy := *template |
| 111 b.beMap[template.Desc.Name] = &templateCopy |
| 112 |
| 113 // Pay the up-front cost of the template. |
| 114 b.beSizes[template.Desc.Name] += protoSize(&templateCopy) |
| 115 return &templateCopy |
| 116 } |
| OLD | NEW |