-
Notifications
You must be signed in to change notification settings - Fork 55
/
cache.go
131 lines (114 loc) · 4.84 KB
/
cache.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
Copyright The Ratify Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package oras
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/deislabs/ratify/errors"
"github.com/deislabs/ratify/internal/logger"
"github.com/deislabs/ratify/pkg/cache"
"github.com/deislabs/ratify/pkg/common"
"github.com/deislabs/ratify/pkg/ocispecs"
"github.com/deislabs/ratify/pkg/referrerstore"
)
const defaultTTL = 10
type orasStoreWithInMemoryCache struct {
referrerstore.ReferrerStore
cacheConf *cacheConf
}
type cacheConf struct {
Enabled bool `json:"cacheEnabled"`
TTL int `json:"ttl"`
}
// createCachedStore creates a new oras store decorated with in-memory cache to cache
// results of ListReferrers API.
func createCachedStore(storeBase referrerstore.ReferrerStore, cacheConf *cacheConf) (referrerstore.ReferrerStore, error) {
return &orasStoreWithInMemoryCache{
ReferrerStore: storeBase,
cacheConf: cacheConf,
}, nil
}
func (store *orasStoreWithInMemoryCache) ListReferrers(ctx context.Context, subjectReference common.Reference, artifactTypes []string, nextToken string, subjectDesc *ocispecs.SubjectDescriptor) (referrerstore.ListReferrersResult, error) {
var err error
var result referrerstore.ListReferrersResult
cacheKey := fmt.Sprintf(cache.CacheKeyListReferrers, subjectReference.Original)
cacheProvider := cache.GetCacheProvider()
if cacheProvider == nil {
logger.GetLogger(ctx, logOpt).Warnf("failed to get cache provider")
} else {
val, found := cacheProvider.Get(ctx, cacheKey)
if val != "" && found {
if err = json.Unmarshal([]byte(val), &result); err != nil {
logger.GetLogger(ctx, logOpt).Warn(errors.ErrorCodeDataDecodingFailure.NewError(errors.Cache, "", errors.EmptyLink, err, fmt.Sprintf("failed to unmarshal cache value for key %s: %s", cacheKey, val), errors.HideStackTrace))
} else {
logger.GetLogger(ctx, logOpt).Debug("cache hit for list referrers")
return result, nil
}
}
}
logger.GetLogger(ctx, logOpt).Debugf("list referrers cache miss for value: %s", subjectReference.Original)
result, err = store.ReferrerStore.ListReferrers(ctx, subjectReference, artifactTypes, nextToken, subjectDesc)
if err == nil {
if cacheProvider != nil {
if added := cacheProvider.SetWithTTL(ctx, cacheKey, result, time.Duration(store.cacheConf.TTL)*time.Second); !added { // TODO: convert ttl to duration in helm values
logger.GetLogger(ctx, logOpt).Warnf("failed to add cache with key: %+v, val: %+v", cacheKey, result)
}
}
}
return result, err
}
func (store *orasStoreWithInMemoryCache) GetSubjectDescriptor(ctx context.Context, subjectReference common.Reference) (*ocispecs.SubjectDescriptor, error) {
result := &ocispecs.SubjectDescriptor{}
var err error
cacheProvider := cache.GetCacheProvider()
if cacheProvider == nil {
logger.GetLogger(ctx, logOpt).Warnf("failed to get cache provider")
} else {
val, found := cacheProvider.Get(ctx, fmt.Sprintf(cache.CacheKeySubjectDescriptor, subjectReference.Digest))
if val != "" && found {
if err = json.Unmarshal([]byte(val), result); err != nil {
logger.GetLogger(ctx, logOpt).Warn(errors.ErrorCodeDataDecodingFailure.NewError(errors.Cache, "", errors.EmptyLink, err, fmt.Sprintf("failed to unmarshal cache value: %v", val), errors.HideStackTrace))
} else {
logger.GetLogger(ctx, logOpt).Debug("cache hit for subject descriptor")
return result, nil
}
}
}
logger.GetLogger(ctx, logOpt).Debugf("subject descriptor cache miss for value: %s", subjectReference.Original)
result, err = store.ReferrerStore.GetSubjectDescriptor(ctx, subjectReference)
if err == nil {
if cacheProvider != nil {
cacheKey := fmt.Sprintf(cache.CacheKeySubjectDescriptor, result.Digest)
if added := cacheProvider.Set(ctx, cacheKey, *result); !added {
logger.GetLogger(ctx, logOpt).Warnf("failed to add cache with key: %+v, val: %+v", cacheKey, result)
}
}
}
return result, err
}
func toCacheConfig(storePluginConfig map[string]interface{}) (*cacheConf, error) {
bytes, err := json.Marshal(storePluginConfig)
if err != nil {
return nil, fmt.Errorf("failed marshalling store plugin config: %+v to bytes, err: %w", storePluginConfig, err)
}
cacheConf := &cacheConf{}
if err := json.Unmarshal(bytes, cacheConf); err != nil {
return nil, fmt.Errorf("failed unmarshalling to Oras cache config, err: %w", err)
}
if cacheConf.TTL == 0 {
cacheConf.TTL = defaultTTL
}
return cacheConf, nil
}