Skip to content

Commit 009504b

Browse files
Paulo Gomeshiddeco
andcommitted
helm: optimise repository index loading
Avoid validating (and thus loading) indexes if the checksum already exists in storage. In other words, if the YAML is identical to the Artifact in storage, the reconciliation should be a no-op, and therefore can short-circuit long/heavy operations. Co-authored-by: Hidde Beydals <[email protected]> Signed-off-by: Paulo Gomes <[email protected]>
1 parent 3c67efa commit 009504b

File tree

3 files changed

+31
-9
lines changed

3 files changed

+31
-9
lines changed

api/v1beta2/artifact_types.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,24 @@ type Artifact struct {
5656
Size *int64 `json:"size,omitempty"`
5757
}
5858

59-
// HasRevision returns true if the given revision matches the current Revision
60-
// of the Artifact.
59+
// HasRevision returns if the given revision matches the current Revision of
60+
// the Artifact.
6161
func (in *Artifact) HasRevision(revision string) bool {
6262
if in == nil {
6363
return false
6464
}
6565
return in.Revision == revision
6666
}
6767

68+
// HasChecksum returns if the given checksum matches the current Checksum of
69+
// the Artifact.
70+
func (in *Artifact) HasChecksum(checksum string) bool {
71+
if in == nil {
72+
return false
73+
}
74+
return in.Checksum == checksum
75+
}
76+
6877
// ArtifactDir returns the artifact dir path in the form of
6978
// '<kind>/<namespace>/<name>'.
7079
func ArtifactDir(kind, namespace, name string) string {

controllers/helmrepository_controller.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,8 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, obj *sou
398398
return sreconcile.ResultEmpty, e
399399
}
400400
}
401+
402+
// Fetch the repository index from remote.
401403
checksum, err := newChartRepo.CacheIndex()
402404
if err != nil {
403405
e := &serror.Event{
@@ -410,6 +412,15 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, obj *sou
410412
}
411413
*chartRepo = *newChartRepo
412414

415+
// Short-circuit based on the fetched index being an exact match to the
416+
// stored Artifact. This prevents having to unmarshal the YAML to calculate
417+
// the (stable) revision, which is a memory expensive operation.
418+
if obj.GetArtifact().HasChecksum(checksum) {
419+
*artifact = *obj.GetArtifact()
420+
conditions.Delete(obj, sourcev1.FetchFailedCondition)
421+
return sreconcile.ResultSuccess, nil
422+
}
423+
413424
// Load the cached repository index to ensure it passes validation.
414425
if err := chartRepo.LoadFromCache(); err != nil {
415426
e := &serror.Event{
@@ -419,23 +430,24 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, obj *sou
419430
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, e.Err.Error())
420431
return sreconcile.ResultEmpty, e
421432
}
422-
defer chartRepo.Unload()
433+
chartRepo.Unload()
423434

424435
// Mark observations about the revision on the object.
425-
if !obj.GetArtifact().HasRevision(checksum) {
436+
if !obj.GetArtifact().HasRevision(newChartRepo.Checksum) {
426437
message := fmt.Sprintf("new index revision '%s'", checksum)
427438
conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "NewRevision", message)
428439
conditions.MarkReconciling(obj, "NewRevision", message)
429440
}
430441

431-
conditions.Delete(obj, sourcev1.FetchFailedCondition)
432-
433442
// Create potential new artifact.
434443
*artifact = r.Storage.NewArtifactFor(obj.Kind,
435444
obj.ObjectMeta.GetObjectMeta(),
436445
chartRepo.Checksum,
437446
fmt.Sprintf("index-%s.yaml", checksum))
438447

448+
// Delete any stale failure observation
449+
conditions.Delete(obj, sourcev1.FetchFailedCondition)
450+
439451
return sreconcile.ResultSuccess, nil
440452
}
441453

@@ -462,7 +474,7 @@ func (r *HelmRepositoryReconciler) reconcileArtifact(ctx context.Context, obj *s
462474
}
463475
}()
464476

465-
if obj.GetArtifact().HasRevision(artifact.Revision) {
477+
if obj.GetArtifact().HasRevision(artifact.Revision) && obj.GetArtifact().HasChecksum(artifact.Checksum) {
466478
r.eventLogf(ctx, obj, events.EventTypeTrace, sourcev1.ArtifactUpToDateReason, "artifact up-to-date with remote revision: '%s'", artifact.Revision)
467479
return sreconcile.ResultSuccess, nil
468480
}

internal/helm/repository/chart_repository.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ type ChartRepository struct {
6666
// Index contains a loaded chart repository index if not nil.
6767
Index *repo.IndexFile
6868
// Checksum contains the SHA256 checksum of the loaded chart repository
69-
// index bytes.
69+
// index bytes. This is different from the checksum of the CachePath, which
70+
// may contain unordered entries.
7071
Checksum string
7172

7273
tlsConfig *tls.Config
@@ -87,7 +88,7 @@ type cacheInfo struct {
8788
RecordIndexCacheMetric RecordMetricsFunc
8889
}
8990

90-
// ChartRepositoryOptions is a function that can be passed to NewChartRepository
91+
// ChartRepositoryOption is a function that can be passed to NewChartRepository
9192
// to configure a ChartRepository.
9293
type ChartRepositoryOption func(*ChartRepository) error
9394

0 commit comments

Comments
 (0)