Chromium Code Reviews| Index: client/internal/logdog/butler/bundler/builder.go |
| diff --git a/client/internal/logdog/butler/bundler/builder.go b/client/internal/logdog/butler/bundler/builder.go |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..d80f766f393070da45ced53875cf069accffd895 |
| --- /dev/null |
| +++ b/client/internal/logdog/butler/bundler/builder.go |
| @@ -0,0 +1,116 @@ |
| +// 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 ( |
| + "fmt" |
| + "sort" |
| + |
| + "github.com/luci/luci-go/common/logdog/protocol" |
| +) |
| + |
| +// builder incrementally constructs ButlerLogBundle entries. |
| +type builder struct { |
| + // template is the base bundle template. |
| + template protocol.ButlerLogBundle |
| + // size is the maximum permitted bundle size. |
| + size int |
| + |
| + // templateCachedSize is the cached size of the ButlerLogBundle template. |
| + templateCachedSize int |
|
iannucci
2015/11/13 07:16:38
this should go up near template. I thought it was
dnj
2015/11/14 00:30:36
Done.
|
| + // entries is the set of ButlerLogBundle_Entry stream state. |
| + beMap map[string]*protocol.ButlerLogBundle_Entry |
|
iannucci
2015/11/13 07:16:38
comment what the 'string' is?
dnj
2015/11/14 00:30:36
Done.
|
| + // beSizes tracks the size of a ButlerLogBundle_Entry. |
| + beSizes map[string]int |
| +} |
| + |
| +func (b *builder) remaining() int { |
| + return b.size - b.bundleSize() |
| +} |
| + |
| +func (b *builder) ready() bool { |
| + // Have we reached our desired size? |
| + return b.hasContent() && (b.bundleSize() >= b.size) |
| +} |
| + |
| +func (b *builder) bundleSize() int { |
| + if b.templateCachedSize == 0 { |
| + b.templateCachedSize = protoSize(&b.template) |
| + } |
| + |
| + size := b.templateCachedSize |
| + for _, sz := range b.beSizes { |
| + size += sizeOfBundleEntryTag + varintLength(uint64(sz)) + sz |
| + } |
| + |
| + return size |
| +} |
| + |
| +func (b *builder) hasContent() bool { |
| + return len(b.beMap) > 0 |
| +} |
| + |
| +func (b *builder) add(template *protocol.ButlerLogBundle_Entry, le *protocol.LogEntry) { |
| + be := b.getCreateBundleEntry(template) |
| + |
| + be.Logs = append(be.Logs, le) |
| + psize := protoSize(le) |
| + |
| + // Pay the cost of the additional LogEntry. |
| + b.beSizes[template.Desc.Name] += sizeOfLogEntryTag + varintLength(uint64(psize)) + psize |
| +} |
| + |
| +func (b *builder) setStreamTerminal(template *protocol.ButlerLogBundle_Entry, tidx uint64) { |
| + be := b.getCreateBundleEntry(template) |
| + if be.Terminal { |
| + if be.TerminalIndex != tidx { |
| + panic(fmt.Errorf("attempt to change terminal index %d => %d", be.TerminalIndex, tidx)) |
| + } |
| + return |
| + } |
| + |
| + be.Terminal = true |
| + be.TerminalIndex = tidx |
| + |
| + // Pay the cost of the additional terminal fields. |
| + b.beSizes[template.Desc.Name] += (sizeOfTerminalTag + sizeOfBoolTrue + |
| + sizeOfTerminalIndexTag + varintLength(be.TerminalIndex)) |
| +} |
| + |
| +func (b *builder) bundle() *protocol.ButlerLogBundle { |
| + bundle := b.template |
| + |
| + names := make([]string, 0, len(b.beMap)) |
| + for k := range b.beMap { |
| + names = append(names, k) |
| + } |
| + sort.Strings(names) |
| + |
| + bundle.Entries = make([]*protocol.ButlerLogBundle_Entry, len(names)) |
| + for idx, name := range names { |
| + bundle.Entries[idx] = b.beMap[name] |
| + } |
| + |
| + return &bundle |
| +} |
| + |
| +func (b *builder) getCreateBundleEntry(template *protocol.ButlerLogBundle_Entry) *protocol.ButlerLogBundle_Entry { |
| + if be := b.beMap[template.Desc.Name]; be != nil { |
| + return be |
| + } |
| + |
| + // Initialize our maps (first time only). |
| + if b.beMap == nil { |
| + b.beMap = map[string]*protocol.ButlerLogBundle_Entry{} |
| + b.beSizes = map[string]int{} |
| + } |
| + |
| + templateCopy := *template |
| + b.beMap[template.Desc.Name] = &templateCopy |
| + |
| + // Pay the up-front cost of the template. |
| + b.beSizes[template.Desc.Name] += protoSize(&templateCopy) |
| + return &templateCopy |
| +} |