diff --git a/report/map_helpers.go b/report/map_helpers.go index 480ddcf26..6bd77c50b 100644 --- a/report/map_helpers.go +++ b/report/map_helpers.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "sort" + "time" "github.com/ugorji/go/codec" "github.com/weaveworks/ps" @@ -138,3 +139,58 @@ func mapWrite(m ps.Map, encoder *codec.Encoder, encodeValue func(*codec.Encoder, }) z.EncSendContainerState(containerMapEnd) } + +// Now follow helpers for StringLatestMap + +// stringPairs lets us sort a slice of (key,value) strings by key +type stringPairs []string + +func (m stringPairs) Len() int { return len(m) / 2 } +func (m stringPairs) Swap(i, j int) { + m[i*2], m[i*2+1], m[j*2], m[j*2+1] = m[j*2], m[j*2+1], m[i*2], m[i*2+1] +} +func (m stringPairs) Less(i, j int) bool { return m[i*2] < m[j*2] } + +// SetMulti takes a list of pairs (key, value) and adds them at time t. +func (m StringLatestMap) SetMulti(t time.Time, n ...string) StringLatestMap { + // Optimise the special case of one value + if len(n) == 2 { + return m.Set(n[0], t, n[1]) + } + if len(n)%2 != 0 { + // panic because this is a coding error + panic("StringLatestMap.SetMulti must be called with pairs of strings") + } + // We need values sorted by key so we can do a merge; check first so callers can avoid this step + if !sort.IsSorted(stringPairs(n)) { + sort.Sort(stringPairs(n)) + } + l := len(m) + out := make([]stringLatestEntry, 0, l+len(n)/2) + + // this bit is identical to Merge(), except the j-index moves by two steps each time + i, j := 0, 0 + for i < len(m) { + switch { + case j >= len(n) || m[i].key < n[j]: + out = append(out, m[i]) + i++ + case m[i].key == n[j]: + if m[i].Timestamp.Before(t) { + out = append(out, stringLatestEntry{key: n[j], Value: n[j+1], Timestamp: t}) + } else { + out = append(out, m[i]) + } + i++ + j += 2 + default: + out = append(out, stringLatestEntry{key: n[j], Value: n[j+1], Timestamp: t}) + j += 2 + } + } + for j < len(n) { + out = append(out, stringLatestEntry{key: n[j], Value: n[j+1], Timestamp: t}) + j += 2 + } + return out +} diff --git a/report/node.go b/report/node.go index 94fcb5c58..6cff3594e 100644 --- a/report/node.go +++ b/report/node.go @@ -39,8 +39,8 @@ func MakeNode(id string) Node { } // MakeNodeWith creates a new Node with the supplied map. -func MakeNodeWith(id string, m map[string]string) Node { - return MakeNode(id).WithLatests(m) +func MakeNodeWith(id string, m ...string) Node { + return MakeNode(id).WithLatests(m...) } // WithID returns a fresh copy of n, with ID changed. @@ -70,12 +70,9 @@ func (n Node) After(other Node) bool { return other.Topology < n.Topology || (other.Topology == n.Topology && other.ID < n.ID) } -// WithLatests returns a fresh copy of n, with Metadata m merged in. -func (n Node) WithLatests(m map[string]string) Node { - ts := mtime.Now() - for k, v := range m { - n.Latest = n.Latest.Set(k, ts, v) - } +// WithLatests returns a fresh copy of n, with Metadata m (pairs of key,value) merged in. +func (n Node) WithLatests(m ...string) Node { + n.Latest = n.Latest.SetMulti(mtime.Now(), m...) return n }