mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-03 18:20:27 +00:00
Move merge functions with their types
This commit is contained in:
116
report/merge.go
116
report/merge.go
@@ -1,116 +0,0 @@
|
||||
package report
|
||||
|
||||
// Merge functions for all topology datatypes. The general semantics are that
|
||||
// the receiver is modified, and what's merged in isn't.
|
||||
|
||||
// Merge merges another Report into the receiver. Pass addWindows true if the
|
||||
// reports represent distinct (non-overlapping) periods of time.
|
||||
func (r *Report) Merge(other Report) {
|
||||
r.Endpoint.Merge(other.Endpoint)
|
||||
r.Address.Merge(other.Address)
|
||||
r.Process.Merge(other.Process)
|
||||
r.Container.Merge(other.Container)
|
||||
r.ContainerImage.Merge(other.ContainerImage)
|
||||
r.Host.Merge(other.Host)
|
||||
r.Overlay.Merge(other.Overlay)
|
||||
r.Sampling.Merge(other.Sampling)
|
||||
r.Window += other.Window
|
||||
}
|
||||
|
||||
// Merge merges another Topology into the receiver.
|
||||
func (t *Topology) Merge(other Topology) {
|
||||
t.Adjacency.Merge(other.Adjacency)
|
||||
t.EdgeMetadatas.Merge(other.EdgeMetadatas)
|
||||
t.NodeMetadatas.Merge(other.NodeMetadatas)
|
||||
}
|
||||
|
||||
// Merge merges another Adjacency list into the receiver.
|
||||
func (a *Adjacency) Merge(other Adjacency) {
|
||||
for addr, adj := range other {
|
||||
(*a)[addr] = (*a)[addr].Merge(adj)
|
||||
}
|
||||
}
|
||||
|
||||
// Merge merges another NodeMetadatas into the receiver.
|
||||
func (m *NodeMetadatas) Merge(other NodeMetadatas) {
|
||||
for id, meta := range other {
|
||||
if _, ok := (*m)[id]; !ok {
|
||||
(*m)[id] = meta // not a copy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Merge merges two node metadata maps together. In case of conflict, the
|
||||
// other (right-hand) side wins. Always reassign the result of merge to the
|
||||
// destination. Merge is defined on the value-type, but node metadata map is
|
||||
// itself a reference type, so if you want to maintain immutability, use copy.
|
||||
func (nm NodeMetadata) Merge(other NodeMetadata) NodeMetadata {
|
||||
for k, v := range other.Metadata {
|
||||
nm.Metadata[k] = v // other takes precedence
|
||||
}
|
||||
for k, v := range other.Counters {
|
||||
nm.Counters[k] = nm.Counters[k] + v
|
||||
}
|
||||
return nm
|
||||
}
|
||||
|
||||
// Merge merges another EdgeMetadatas into the receiver. If other is from
|
||||
// another probe this is the union of both metadatas. Keys present in both are
|
||||
// summed.
|
||||
func (e *EdgeMetadatas) Merge(other EdgeMetadatas) {
|
||||
for id, edgemeta := range other {
|
||||
local := (*e)[id]
|
||||
local.Merge(edgemeta)
|
||||
(*e)[id] = local
|
||||
}
|
||||
}
|
||||
|
||||
// Merge merges another EdgeMetadata into the receiver. The two edge metadatas
|
||||
// should represent the same edge on different times.
|
||||
func (m *EdgeMetadata) Merge(other EdgeMetadata) {
|
||||
m.EgressPacketCount = merge(m.EgressPacketCount, other.EgressPacketCount, sum)
|
||||
m.IngressPacketCount = merge(m.IngressPacketCount, other.IngressPacketCount, sum)
|
||||
m.EgressByteCount = merge(m.EgressByteCount, other.EgressByteCount, sum)
|
||||
m.IngressByteCount = merge(m.IngressByteCount, other.IngressByteCount, sum)
|
||||
m.MaxConnCountTCP = merge(m.MaxConnCountTCP, other.MaxConnCountTCP, max)
|
||||
}
|
||||
|
||||
// Flatten sums two EdgeMetadatas. Their windows should be the same duration;
|
||||
// they should represent different edges at the same time.
|
||||
func (m *EdgeMetadata) Flatten(other EdgeMetadata) {
|
||||
m.EgressPacketCount = merge(m.EgressPacketCount, other.EgressPacketCount, sum)
|
||||
m.IngressPacketCount = merge(m.IngressPacketCount, other.IngressPacketCount, sum)
|
||||
m.EgressByteCount = merge(m.EgressByteCount, other.EgressByteCount, sum)
|
||||
m.IngressByteCount = merge(m.IngressByteCount, other.IngressByteCount, sum)
|
||||
// Note that summing of two maximums doesn't always give us the true
|
||||
// maximum. But it's a best effort.
|
||||
m.MaxConnCountTCP = merge(m.MaxConnCountTCP, other.MaxConnCountTCP, sum)
|
||||
}
|
||||
|
||||
// Merge combines two sampling structures via simple addition.
|
||||
func (s *Sampling) Merge(other Sampling) {
|
||||
s.Count += other.Count
|
||||
s.Total += other.Total
|
||||
}
|
||||
|
||||
func merge(dst, src *uint64, op func(uint64, uint64) uint64) *uint64 {
|
||||
if src == nil {
|
||||
return dst
|
||||
}
|
||||
if dst == nil {
|
||||
dst = new(uint64)
|
||||
}
|
||||
(*dst) = op(*dst, *src)
|
||||
return dst
|
||||
}
|
||||
|
||||
func sum(dst, src uint64) uint64 {
|
||||
return dst + src
|
||||
}
|
||||
|
||||
func max(dst, src uint64) uint64 {
|
||||
if dst > src {
|
||||
return dst
|
||||
}
|
||||
return src
|
||||
}
|
||||
@@ -70,6 +70,19 @@ func MakeReport() Report {
|
||||
}
|
||||
}
|
||||
|
||||
// Merge merges another Report into the receiver.
|
||||
func (r *Report) Merge(other Report) {
|
||||
r.Endpoint.Merge(other.Endpoint)
|
||||
r.Address.Merge(other.Address)
|
||||
r.Process.Merge(other.Process)
|
||||
r.Container.Merge(other.Container)
|
||||
r.ContainerImage.Merge(other.ContainerImage)
|
||||
r.Host.Merge(other.Host)
|
||||
r.Overlay.Merge(other.Overlay)
|
||||
r.Sampling.Merge(other.Sampling)
|
||||
r.Window += other.Window
|
||||
}
|
||||
|
||||
// Topologies returns a slice of Topologies in this report
|
||||
func (r Report) Topologies() []Topology {
|
||||
return []Topology{
|
||||
@@ -118,6 +131,12 @@ func (s Sampling) Rate() float64 {
|
||||
return float64(s.Count) / float64(s.Total)
|
||||
}
|
||||
|
||||
// Merge combines two sampling structures via simple addition.
|
||||
func (s *Sampling) Merge(other Sampling) {
|
||||
s.Count += other.Count
|
||||
s.Total += other.Total
|
||||
}
|
||||
|
||||
const (
|
||||
// HostNodeID is a metadata foreign key, linking a node in any topology to
|
||||
// a node in the host topology. That host node is the origin host, where
|
||||
|
||||
@@ -5,8 +5,6 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const localUnknown = "localUnknown"
|
||||
|
||||
// Topology describes a specific view of a network. It consists of nodes and
|
||||
// edges, represented by Adjacency, and metadata about those nodes and edges,
|
||||
// represented by EdgeMetadatas and NodeMetadatas respectively.
|
||||
@@ -16,18 +14,52 @@ type Topology struct {
|
||||
NodeMetadatas
|
||||
}
|
||||
|
||||
// Merge merges another Topology into the receiver.
|
||||
func (t *Topology) Merge(other Topology) {
|
||||
t.Adjacency.Merge(other.Adjacency)
|
||||
t.EdgeMetadatas.Merge(other.EdgeMetadatas)
|
||||
t.NodeMetadatas.Merge(other.NodeMetadatas)
|
||||
}
|
||||
|
||||
// Adjacency is an adjacency-list encoding of the topology. Keys are node IDs,
|
||||
// as produced by the relevant MappingFunc for the topology.
|
||||
type Adjacency map[string]IDList
|
||||
|
||||
// Merge merges another Adjacency list into the receiver.
|
||||
func (a *Adjacency) Merge(other Adjacency) {
|
||||
for addr, adj := range other {
|
||||
(*a)[addr] = (*a)[addr].Merge(adj)
|
||||
}
|
||||
}
|
||||
|
||||
// EdgeMetadatas collect metadata about each edge in a topology. Keys are a
|
||||
// concatenation of node IDs.
|
||||
type EdgeMetadatas map[string]EdgeMetadata
|
||||
|
||||
// Merge merges another EdgeMetadatas into the receiver. If other is from
|
||||
// another probe this is the union of both metadatas. Keys present in both are
|
||||
// summed.
|
||||
func (e *EdgeMetadatas) Merge(other EdgeMetadatas) {
|
||||
for id, edgemeta := range other {
|
||||
local := (*e)[id]
|
||||
local.Merge(edgemeta)
|
||||
(*e)[id] = local
|
||||
}
|
||||
}
|
||||
|
||||
// NodeMetadatas collect metadata about each node in a topology. Keys are node
|
||||
// IDs.
|
||||
type NodeMetadatas map[string]NodeMetadata
|
||||
|
||||
// Merge merges another NodeMetadatas into the receiver.
|
||||
func (m *NodeMetadatas) Merge(other NodeMetadatas) {
|
||||
for id, meta := range other {
|
||||
if _, ok := (*m)[id]; !ok {
|
||||
(*m)[id] = meta // not a copy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EdgeMetadata describes a superset of the metadata that probes can possibly
|
||||
// collect about a directed edge between two nodes in any topology.
|
||||
type EdgeMetadata struct {
|
||||
@@ -38,6 +70,28 @@ type EdgeMetadata struct {
|
||||
MaxConnCountTCP *uint64 `json:"max_conn_count_tcp,omitempty"`
|
||||
}
|
||||
|
||||
// Merge merges another EdgeMetadata into the receiver. The two edge metadatas
|
||||
// should represent the same edge on different times.
|
||||
func (m *EdgeMetadata) Merge(other EdgeMetadata) {
|
||||
m.EgressPacketCount = merge(m.EgressPacketCount, other.EgressPacketCount, sum)
|
||||
m.IngressPacketCount = merge(m.IngressPacketCount, other.IngressPacketCount, sum)
|
||||
m.EgressByteCount = merge(m.EgressByteCount, other.EgressByteCount, sum)
|
||||
m.IngressByteCount = merge(m.IngressByteCount, other.IngressByteCount, sum)
|
||||
m.MaxConnCountTCP = merge(m.MaxConnCountTCP, other.MaxConnCountTCP, max)
|
||||
}
|
||||
|
||||
// Flatten sums two EdgeMetadatas. Their windows should be the same duration;
|
||||
// they should represent different edges at the same time.
|
||||
func (m *EdgeMetadata) Flatten(other EdgeMetadata) {
|
||||
m.EgressPacketCount = merge(m.EgressPacketCount, other.EgressPacketCount, sum)
|
||||
m.IngressPacketCount = merge(m.IngressPacketCount, other.IngressPacketCount, sum)
|
||||
m.EgressByteCount = merge(m.EgressByteCount, other.EgressByteCount, sum)
|
||||
m.IngressByteCount = merge(m.IngressByteCount, other.IngressByteCount, sum)
|
||||
// Note that summing of two maximums doesn't always give us the true
|
||||
// maximum. But it's a best effort.
|
||||
m.MaxConnCountTCP = merge(m.MaxConnCountTCP, other.MaxConnCountTCP, sum)
|
||||
}
|
||||
|
||||
// NodeMetadata describes a superset of the metadata that probes can collect
|
||||
// about a given node in a given topology.
|
||||
type NodeMetadata struct {
|
||||
@@ -58,6 +112,20 @@ func MakeNodeMetadataWith(m map[string]string) NodeMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
// Merge merges two node metadata maps together. In case of conflict, the
|
||||
// other (right-hand) side wins. Always reassign the result of merge to the
|
||||
// destination. Merge is defined on the value-type, but node metadata map is
|
||||
// itself a reference type, so if you want to maintain immutability, use copy.
|
||||
func (nm NodeMetadata) Merge(other NodeMetadata) NodeMetadata {
|
||||
for k, v := range other.Metadata {
|
||||
nm.Metadata[k] = v // other takes precedence
|
||||
}
|
||||
for k, v := range other.Counters {
|
||||
nm.Counters[k] = nm.Counters[k] + v
|
||||
}
|
||||
return nm
|
||||
}
|
||||
|
||||
// Copy returns a value copy, useful for tests.
|
||||
func (nm NodeMetadata) Copy() NodeMetadata {
|
||||
cp := MakeNodeMetadata()
|
||||
@@ -140,3 +208,25 @@ func (t Topology) Validate() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func merge(dst, src *uint64, op func(uint64, uint64) uint64) *uint64 {
|
||||
if src == nil {
|
||||
return dst
|
||||
}
|
||||
if dst == nil {
|
||||
dst = new(uint64)
|
||||
}
|
||||
(*dst) = op(*dst, *src)
|
||||
return dst
|
||||
}
|
||||
|
||||
func sum(dst, src uint64) uint64 {
|
||||
return dst + src
|
||||
}
|
||||
|
||||
func max(dst, src uint64) uint64 {
|
||||
if dst > src {
|
||||
return dst
|
||||
}
|
||||
return src
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user