Always merge into the larger ps.Map

Because they are commutative and immutable, we can do this!
This commit is contained in:
Paul Bellamy
2016-01-25 15:25:01 +00:00
parent 728572cb51
commit 5751db2a5a
5 changed files with 87 additions and 24 deletions

View File

@@ -48,19 +48,35 @@ func (c Counters) Lookup(key string) (int, bool) {
return 0, false
}
// Size returns the number of counters
func (c Counters) Size() int {
return c.psMap.Size()
}
// Merge produces a fresh Counters, container the keys from both inputs. When
// both inputs container the same key, the latter value is used.
func (c Counters) Merge(other Counters) Counters {
output := c.psMap
other.psMap.ForEach(func(key string, otherVal interface{}) {
var (
cSize = c.Size()
otherSize = other.Size()
output = c.psMap
iter = other.psMap
)
switch {
case cSize == 0:
return other
case otherSize == 0:
return c
case cSize < otherSize:
output, iter = iter, output
}
iter.ForEach(func(key string, otherVal interface{}) {
if val, ok := output.Lookup(key); ok {
output = output.Set(key, otherVal.(int)+val.(int))
} else {
output = output.Set(key, otherVal)
}
})
return Counters{output}
}

View File

@@ -49,19 +49,35 @@ func (c EdgeMetadatas) Lookup(key string) (EdgeMetadata, bool) {
return EdgeMetadata{}, false
}
// Size is the number of elements
func (c EdgeMetadatas) Size() int {
return c.psMap.Size()
}
// Merge produces a fresh Counters, container the keys from both inputs. When
// both inputs container the same key, the latter value is used.
func (c EdgeMetadatas) Merge(other EdgeMetadatas) EdgeMetadatas {
output := c.psMap
other.psMap.ForEach(func(key string, otherVal interface{}) {
var (
cSize = c.Size()
otherSize = other.Size()
output = c.psMap
iter = other.psMap
)
switch {
case cSize == 0:
return other
case otherSize == 0:
return c
case cSize < otherSize:
output, iter = iter, output
}
iter.ForEach(func(key string, otherVal interface{}) {
if val, ok := output.Lookup(key); ok {
output = output.Set(key, otherVal.(EdgeMetadata).Merge(val.(EdgeMetadata)))
} else {
output = output.Set(key, otherVal)
}
})
return EdgeMetadatas{output}
}

View File

@@ -45,21 +45,36 @@ func (m LatestMap) Copy() LatestMap {
return m
}
// Size returns the number of elements
func (m LatestMap) Size() int {
return m.Map.Size()
}
// Merge produces a fresh LatestMap, container the kers from both inputs. When
// both inputs container the same key, the latter value is used.
func (m LatestMap) Merge(newer LatestMap) LatestMap {
// expect people to do old.Merge(new), optimise for that.
// ie if you do {k: v}.Merge({k: v'}), we end up just returning
// newer, unmodified.
output := newer.Map
func (m LatestMap) Merge(other LatestMap) LatestMap {
var (
mSize = m.Size()
otherSize = other.Size()
output = m.Map
iter = other.Map
)
switch {
case mSize == 0:
return other
case otherSize == 0:
return m
case mSize < otherSize:
output, iter = iter, output
}
m.Map.ForEach(func(key string, olderVal interface{}) {
if newerVal, ok := newer.Map.Lookup(key); ok {
if newerVal.(LatestEntry).Timestamp.Before(olderVal.(LatestEntry).Timestamp) {
output = output.Set(key, olderVal)
iter.ForEach(func(key string, iterVal interface{}) {
if existingVal, ok := output.Lookup(key); ok {
if existingVal.(LatestEntry).Timestamp.Before(iterVal.(LatestEntry).Timestamp) {
output = output.Set(key, iterVal)
}
} else {
output = output.Set(key, olderVal)
output = output.Set(key, iterVal)
}
})

View File

@@ -95,10 +95,9 @@ func TestMergeNodes(t *testing.T) {
},
b: report.Nodes{
":192.168.1.1:12345": report.MakeNodeWith(map[string]string{ // <-- same ID
PID: "0",
Name: "curl",
Domain: "node-a.local",
}),
}).WithLatest(PID, time.Now().Add(-1*time.Minute), "0"),
},
want: report.Nodes{
":192.168.1.1:12345": report.MakeNodeWith(map[string]string{
@@ -118,10 +117,9 @@ func TestMergeNodes(t *testing.T) {
},
b: report.Nodes{
":192.168.1.1:12345": report.MakeNodeWith(map[string]string{ // <-- same ID
PID: "0",
Name: "curl",
Domain: "node-a.local",
}),
}).WithLatest(PID, time.Now().Add(-1*time.Minute), "0"),
},
want: report.Nodes{
":192.168.1.1:12345": report.MakeNodeWith(map[string]string{

View File

@@ -48,12 +48,30 @@ func (s Sets) Lookup(key string) (StringSet, bool) {
return EmptyStringSet, false
}
// Size returns the number of elements
func (s Sets) Size() int {
return s.psMap.Size()
}
// Merge merges two sets maps into a fresh set, performing set-union merges as
// appropriate.
func (s Sets) Merge(other Sets) Sets {
result := s.psMap
var (
sSize = s.Size()
otherSize = other.Size()
result = s.psMap
iter = other.psMap
)
switch {
case sSize == 0:
return other
case otherSize == 0:
return s
case sSize < otherSize:
result, iter = iter, result
}
other.psMap.ForEach(func(key string, value interface{}) {
iter.ForEach(func(key string, value interface{}) {
set := value.(StringSet)
if existingSet, ok := result.Lookup(key); ok {
set = set.Merge(existingSet.(StringSet))