Skip to content

Commit dd191ef

Browse files
committed
Support dependency/redundancy group state checksum on the fly
1 parent 732a184 commit dd191ef

File tree

4 files changed

+57
-12
lines changed

4 files changed

+57
-12
lines changed

pkg/contracts/contracts.go

+7
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,10 @@ func SafeInit(v any) {
2727
initer.Init()
2828
}
2929
}
30+
31+
// Equaler is implemented by any entity that can be compared with another entity of the same type.
32+
// The Equal method should return true if the receiver is equal to the other entity.
33+
type Equaler interface {
34+
// Equal returns whether the receiver is equal to the other entity.
35+
Equal(other any) bool
36+
}

pkg/icingadb/delta.go

+13-7
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func (delta *Delta) run(ctx context.Context, actualCh, desiredCh <-chan database
5353
desired := EntitiesById{} // only read from desiredCh (so far)
5454

5555
var update EntitiesById
56-
if delta.Subject.WithChecksum() {
56+
if _, ok := delta.Subject.Entity().(contracts.Equaler); ok || delta.Subject.WithChecksum() {
5757
update = EntitiesById{} // read from actualCh and desiredCh with mismatching checksums
5858
}
5959

@@ -70,7 +70,7 @@ func (delta *Delta) run(ctx context.Context, actualCh, desiredCh <-chan database
7070
id := actualValue.ID().String()
7171
if desiredValue, ok := desired[id]; ok {
7272
delete(desired, id)
73-
if update != nil && !checksumsMatch(actualValue, desiredValue) {
73+
if update != nil && !entitiesEqual(actualValue, desiredValue) {
7474
update[id] = desiredValue
7575
}
7676
} else {
@@ -88,7 +88,7 @@ func (delta *Delta) run(ctx context.Context, actualCh, desiredCh <-chan database
8888
id := desiredValue.ID().String()
8989
if actualValue, ok := actual[id]; ok {
9090
delete(actual, id)
91-
if update != nil && !checksumsMatch(actualValue, desiredValue) {
91+
if update != nil && !entitiesEqual(actualValue, desiredValue) {
9292
update[id] = desiredValue
9393
}
9494
} else {
@@ -117,8 +117,14 @@ func (delta *Delta) run(ctx context.Context, actualCh, desiredCh <-chan database
117117
zap.Int("delete", len(delta.Delete)))
118118
}
119119

120-
// checksumsMatch returns whether the checksums of two entities are the same.
121-
// Both entities must implement contracts.Checksumer.
122-
func checksumsMatch(a, b database.Entity) bool {
123-
return cmp.Equal(a.(contracts.Checksumer).Checksum(), b.(contracts.Checksumer).Checksum())
120+
// entitiesEqual returns whether the two entities are equal either based on their checksum or by comparing them.
121+
//
122+
// Both entities must either implement contracts.Checksumer or contracts.Equaler for this to work. If neither
123+
// interface is implemented nor if both entities don't implement the same interface, this function will panic.
124+
func entitiesEqual(a, b database.Entity) bool {
125+
if _, ok := a.(contracts.Checksumer); ok {
126+
return cmp.Equal(a.(contracts.Checksumer).Checksum(), b.(contracts.Checksumer).Checksum())
127+
}
128+
129+
return a.(contracts.Equaler).Equal(b)
124130
}

pkg/icingadb/sync.go

+12-3
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,18 @@ func (s Sync) ApplyDelta(ctx context.Context, delta *Delta) error {
148148
entitiesWithoutChecksum, errs := icingaredis.CreateEntities(ctx, delta.Subject.Factory(), pairs, runtime.NumCPU())
149149
// Let errors from CreateEntities cancel our group.
150150
com.ErrgroupReceive(g, errs)
151-
entities, errs := icingaredis.SetChecksums(ctx, entitiesWithoutChecksum, delta.Update, runtime.NumCPU())
152-
// Let errors from SetChecksums cancel our group.
153-
com.ErrgroupReceive(g, errs)
151+
152+
var entities <-chan database.Entity
153+
// Apply the checksums only if the sync subject supports it, i.e, it implements contracts.Checksumer.
154+
// This is necessary because not only entities that implement contracts.Checksumer can be updated, but
155+
// also entities that implement contracts.Equaler interface.
156+
if delta.Subject.WithChecksum() {
157+
entities, errs = icingaredis.SetChecksums(ctx, entitiesWithoutChecksum, delta.Update, runtime.NumCPU())
158+
// Let errors from SetChecksums cancel our group.
159+
com.ErrgroupReceive(g, errs)
160+
} else {
161+
entities = entitiesWithoutChecksum
162+
}
154163

155164
g.Go(func() error {
156165
// Using upsert here on purpose as this is the fastest way to do bulk updates.

pkg/icingadb/v1/dependency.go

+25-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package v1
22

33
import (
4+
"bytes"
5+
"github.com/google/go-cmp/cmp"
46
"github.com/icinga/icinga-go-library/database"
57
"github.com/icinga/icinga-go-library/types"
68
)
@@ -12,7 +14,7 @@ type Redundancygroup struct {
1214
}
1315

1416
// TableName implements [database.TableNamer].
15-
func (r Redundancygroup) TableName() string {
17+
func (r *Redundancygroup) TableName() string {
1618
return "redundancy_group"
1719
}
1820

@@ -26,10 +28,22 @@ type RedundancygroupState struct {
2628
}
2729

2830
// TableName implements [database.TableNamer].
29-
func (r RedundancygroupState) TableName() string {
31+
func (r *RedundancygroupState) TableName() string {
3032
return "redundancy_group_state"
3133
}
3234

35+
// Equal implements the [contracts.Equaler] interface.
36+
func (r *RedundancygroupState) Equal(other any) bool {
37+
if other, ok := other.(*RedundancygroupState); ok {
38+
return bytes.Equal(r.RedundancyGroupId, other.RedundancyGroupId) &&
39+
cmp.Equal(r.Failed, other.Failed) &&
40+
cmp.Equal(r.IsReachable, other.IsReachable) &&
41+
r.LastStateChange.Time().Equal(other.LastStateChange.Time())
42+
}
43+
44+
return false
45+
}
46+
3347
type DependencyNode struct {
3448
EntityWithoutChecksum `json:",inline"`
3549
EnvironmentMeta `json:",inline"`
@@ -44,6 +58,15 @@ type DependencyEdgeState struct {
4458
Failed types.Bool `json:"failed"`
4559
}
4660

61+
// Equal implements the [contracts.Equaler] interface.
62+
func (es *DependencyEdgeState) Equal(other any) bool {
63+
if other, ok := other.(*DependencyEdgeState); ok {
64+
return bytes.Equal(es.Id, other.Id) && cmp.Equal(es.Failed, other.Failed)
65+
}
66+
67+
return false
68+
}
69+
4770
type DependencyEdge struct {
4871
EntityWithoutChecksum `json:",inline"`
4972
EnvironmentMeta `json:",inline"`

0 commit comments

Comments
 (0)