diff --git a/chart/kubeapps/values.yaml b/chart/kubeapps/values.yaml index 757ecfcd4db..6ec63be45b3 100644 --- a/chart/kubeapps/values.yaml +++ b/chart/kubeapps/values.yaml @@ -167,7 +167,7 @@ tillerProxy: resources: limits: cpu: 250m - memory: 128Mi + memory: 256Mi requests: cpu: 25m memory: 32Mi diff --git a/pkg/chart/chart.go b/pkg/chart/chart.go index 49617e42fd8..8bee5c71e1a 100644 --- a/pkg/chart/chart.go +++ b/pkg/chart/chart.go @@ -18,6 +18,7 @@ package chart import ( "bytes" + "crypto/sha256" "crypto/tls" "crypto/x509" "encoding/json" @@ -45,6 +46,17 @@ const ( defaultTimeoutSeconds = 180 ) +type repoIndex struct { + checksum string + index *repo.IndexFile +} + +var repoIndexes map[string]*repoIndex + +func init() { + repoIndexes = map[string]*repoIndex{} +} + // Details contains the information to retrieve a Chart type Details struct { // RepoURL is the URL of the repository. Defaults to stable repo. @@ -145,6 +157,27 @@ func readResponseBody(res *http.Response) ([]byte, error) { return body, nil } +func checksum(data []byte) string { + hasher := sha256.New() + hasher.Write(data) + return string(hasher.Sum(nil)) +} + +// Cache the result of parsing the repo index since parsing this YAML +// is an expensive operation. See https://github.com/kubeapps/kubeapps/issues/1052 +func getIndexFromCache(repoURL string, data []byte) (*repo.IndexFile, string) { + sha := checksum(data) + if repoIndexes[repoURL] == nil || repoIndexes[repoURL].checksum != sha { + // The repository is not in the cache or the content changed + return nil, sha + } + return repoIndexes[repoURL].index, sha +} + +func storeIndexInCache(repoURL string, index *repo.IndexFile, sha string) { + repoIndexes[repoURL] = &repoIndex{sha, index} +} + func parseIndex(data []byte) (*repo.IndexFile, error) { index := &repo.IndexFile{} err := yaml.Unmarshal(data, index) @@ -171,7 +204,16 @@ func fetchRepoIndex(netClient *HTTPClient, repoURL string, authHeader string) (* return nil, err } - return parseIndex(data) + index, sha := getIndexFromCache(repoURL, data) + if index == nil { + // index not found in the cache, parse it + index, err = parseIndex(data) + if err != nil { + return nil, err + } + storeIndexInCache(repoURL, index, sha) + } + return index, nil } func resolveChartURL(index, chart string) (string, error) { diff --git a/pkg/chart/chart_test.go b/pkg/chart/chart_test.go index 61d458363e4..64731de3d32 100644 --- a/pkg/chart/chart_test.go +++ b/pkg/chart/chart_test.go @@ -242,3 +242,18 @@ func TestGetChartWithCustomUserAgent(t *testing.T) { t.Errorf("It should return a Chart") } } + +func TestGetIndexFromCache(t *testing.T) { + repoURL := "https://test.com" + data := []byte("foo") + index, sha := getIndexFromCache(repoURL, data) + if index != nil { + t.Error("Index should be empty since it's not in the cache yet") + } + fakeIndex := &repo.IndexFile{} + storeIndexInCache(repoURL, fakeIndex, sha) + index, _ = getIndexFromCache(repoURL, data) + if index != fakeIndex { + t.Error("It should return the stored index") + } +}