• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / deployments / 1351052686

27 Jun 2024 03:52PM UTC coverage: 79.696% (-0.06%) from 79.752%
1351052686

Pull #1029

gitlab-ci

alfrunes
perf: Optimize database interactions when updating deployment stats

Changed the sequential find and double update ops with a findAndModify
followed by a conditional update if the status actually changed.
This also improves atomicity as there is an inherent race condition when
doing the deployment status aggregation locally.

I also noticed that most internal calls to UpdateDeviceDeploymentStatus
already has the DeviceDeployment already, so I added an internal
updateDeviceDeploymentStatus which skips fetching the device deployment
(again).

Signed-off-by: Alf-Rune Siqveland <alf.rune@northern.tech>
Pull Request #1029: perf: Optimize database interactions when updating deployment stats

56 of 76 new or added lines in 3 files covered. (73.68%)

349 existing lines in 2 files now uncovered.

8125 of 10195 relevant lines covered (79.7%)

34.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.64
/app/app_os.go
1
// Copyright 2023 Northern.tech AS
2
//
3
//        Licensed under the Apache License, Version 2.0 (the "License");
4
//        you may not use this file except in compliance with the License.
5
//        You may obtain a copy of the License at
6
//
7
//            http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//        Unless required by applicable law or agreed to in writing, software
10
//        distributed under the License is distributed on an "AS IS" BASIS,
11
//        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//        See the License for the specific language governing permissions and
13
//        limitations under the License.
14

15
package app
16

17
import (
18
        "context"
19

20
        "github.com/pkg/errors"
21

22
        "github.com/mendersoftware/go-lib-micro/log"
23

24
        "github.com/mendersoftware/deployments/model"
25
)
26

27
func (d *Deployments) isAlreadyInstalled(
28
        request *model.DeploymentNextRequest,
29
        deviceDeployment *model.DeviceDeployment,
30
) bool {
2✔
31
        if request == nil ||
2✔
32
                request.DeviceProvides == nil ||
2✔
33
                deviceDeployment == nil ||
2✔
34
                deviceDeployment.Image == nil ||
2✔
35
                deviceDeployment.Image.ArtifactMeta == nil {
2✔
36
                return false
×
37
        }
×
38

39
        // check if the device reported same artifact name as the one
40
        // in the artifact selected for a given device deployment
41
        return request.DeviceProvides.ArtifactName == deviceDeployment.Image.ArtifactMeta.Name
2✔
42
}
43

44
func (d *Deployments) handleAlreadyInstalled(
45
        ctx context.Context,
46
        deviceDeployment *model.DeviceDeployment,
47
) error {
2✔
48
        l := log.FromContext(ctx)
2✔
49
        if err := d.updateDeviceDeploymentStatus(
2✔
50
                ctx,
2✔
51
                deviceDeployment,
2✔
52
                model.DeviceDeploymentState{
2✔
53
                        Status: model.DeviceDeploymentStatusAlreadyInst,
2✔
54
                }); err != nil {
2✔
55
                return errors.Wrap(err, "Failed to update deployment status")
×
56
        }
×
57
        if err := d.reindexDevice(ctx, deviceDeployment.DeviceId); err != nil {
2✔
58
                l.Warn(errors.Wrap(err, "failed to trigger a device reindex"))
×
59
        }
×
60
        if err := d.reindexDeployment(ctx, deviceDeployment.DeviceId,
2✔
61
                deviceDeployment.DeploymentId, deviceDeployment.Id); err != nil {
2✔
62
                l.Warn(errors.Wrap(err, "failed to trigger a device reindex"))
×
63
        }
×
64

65
        return nil
2✔
66
}
67

68
// assignArtifact assigns artifact to the device deployment
69
func (d *Deployments) assignArtifact(
70
        ctx context.Context,
71
        deployment *model.Deployment,
72
        deviceDeployment *model.DeviceDeployment,
73
        installed *model.InstalledDeviceDeployment) error {
2✔
74

2✔
75
        // Assign artifact to the device deployment.
2✔
76
        var artifact *model.Image
2✔
77
        var err error
2✔
78

2✔
79
        if err = installed.Validate(); err != nil {
2✔
80
                return err
×
81
        }
×
82

83
        if deviceDeployment.DeploymentId == "" || deviceDeployment.DeviceId == "" {
2✔
84
                return ErrModelInternal
×
85
        }
×
86

87
        // Clear device deployment image
88
        // New artifact will be selected for the device deployment
89
        deviceDeployment.Image = nil
2✔
90

2✔
91
        // First case is for backward compatibility.
2✔
92
        // It is possible that there is old deployment structure in the system.
2✔
93
        // In such case we need to select artifact using name and device type.
2✔
94
        if deployment.Artifacts == nil || len(deployment.Artifacts) == 0 {
3✔
95
                artifact, err = d.db.ImageByNameAndDeviceType(
1✔
96
                        ctx,
1✔
97
                        installed.ArtifactName,
1✔
98
                        installed.DeviceType,
1✔
99
                )
1✔
100
                if err != nil {
1✔
101
                        return errors.Wrap(err, "assigning artifact to device deployment")
×
102
                }
×
103
        } else {
1✔
104
                // Select artifact for the device deployment from artifacts assigned to the deployment.
1✔
105
                artifact, err = d.db.ImageByIdsAndDeviceType(
1✔
106
                        ctx,
1✔
107
                        deployment.Artifacts,
1✔
108
                        installed.DeviceType,
1✔
109
                )
1✔
110
                if err != nil {
1✔
111
                        return errors.Wrap(err, "assigning artifact to device deployment")
×
112
                }
×
113
        }
114

115
        // If not having appropriate image, set noartifact status
116
        if artifact == nil {
2✔
117
                return d.assignNoArtifact(ctx, deviceDeployment)
×
118
        }
×
119

120
        if err := d.db.AssignArtifact(
2✔
121
                ctx,
2✔
122
                deviceDeployment.DeviceId,
2✔
123
                deviceDeployment.DeploymentId,
2✔
124
                artifact,
2✔
125
        ); err != nil {
2✔
126
                return errors.Wrap(err, "Assigning artifact to the device deployment")
×
127
        }
×
128

129
        deviceDeployment.Image = artifact
2✔
130

2✔
131
        return nil
2✔
132
}
133

134
func (d *Deployments) assignNoArtifact(
135
        ctx context.Context,
136
        deviceDeployment *model.DeviceDeployment,
137
) error {
×
138
        l := log.FromContext(ctx)
×
NEW
139
        if err := d.updateDeviceDeploymentStatus(ctx, deviceDeployment,
×
140
                model.DeviceDeploymentState{
×
141
                        Status: model.DeviceDeploymentStatusNoArtifact,
×
142
                }); err != nil {
×
143
                return errors.Wrap(err, "Failed to update deployment status")
×
144
        }
×
145
        if err := d.reindexDevice(ctx, deviceDeployment.DeviceId); err != nil {
×
146
                l.Warn(errors.Wrap(err, "failed to trigger a device reindex"))
×
147
        }
×
148
        if err := d.reindexDeployment(ctx, deviceDeployment.DeviceId,
×
149
                deviceDeployment.DeploymentId, deviceDeployment.Id); err != nil {
×
150
                l := log.FromContext(ctx)
×
151
                l.Warn(errors.Wrap(err, "failed to trigger a device reindex"))
×
152
        }
×
153
        return nil
×
154
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc