/
cache.go
112 lines (94 loc) · 2.78 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
package plugin
import (
"fmt"
"sync"
"time"
"github.com/drone/drone-go/drone"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
)
const (
msgCacheHit = "%s config-cache found entry for %s"
msgCacheExpire = "config-cache expired entry for %s"
msgCacheAdd = "%s config-cache added entry for %s"
)
// configCache is used to cache config responses on a per request basis
type configCache struct {
syncMap sync.Map
}
// cacheKey holds the unique key details which are associated with the config request
type cacheKey struct {
slug string
ref string
before string
after string
event string
trigger string
author string
}
// cacheEntry holds the response and ttl for a config request
type cacheEntry struct {
config string
error error
ttl *time.Timer
}
// newCacheEntry creates a new cacheEntry using the config string and error provided. The returned struct will have a
// nil ttl value -- it will be established when a entry is added to the cache via the add function.
func newCacheEntry(config string, error error) *cacheEntry {
entry := &cacheEntry{
config: config,
error: error,
}
return entry
}
// newCacheKey creates a new cacheKey for the provided request.
func newCacheKey(req *request) cacheKey {
ck := cacheKey{
slug: req.Repo.Slug,
ref: req.Build.Ref,
before: req.Build.Before,
after: req.Build.After,
event: req.Build.Event,
author: req.Build.Author,
trigger: req.Build.Trigger,
}
return ck
}
// add an entry to the cache
func (c *configCache) add(uuid uuid.UUID, key cacheKey, entry *cacheEntry, ttl time.Duration) {
logrus.Infof(msgCacheAdd, uuid, fmt.Sprintf("%+v", key))
entry.ttl = time.AfterFunc(ttl, func() {
c.expire(key)
})
c.syncMap.Store(key, entry)
}
// expire is typically called internally via a time.Afterfunc
func (c *configCache) expire(key cacheKey) {
logrus.Infof(msgCacheExpire, fmt.Sprintf("%+v", key))
if entry, _ := c.syncMap.Load(key); entry != nil {
entry.(*cacheEntry).ttl.Stop()
c.syncMap.Delete(key)
}
}
// retrieve an entry from the cache, if it exists
func (c *configCache) retrieve(uuid uuid.UUID, key cacheKey) (*cacheEntry, bool) {
entry, exists := c.syncMap.Load(key)
if exists {
logrus.Infof(msgCacheHit, uuid, fmt.Sprintf("%+v", key))
return entry.(*cacheEntry), true
}
return nil, false
}
// cacheAndReturn caches the result (if enabled) and returns the (drone.Config, error) that should be
// returned to the Find request.
func (p *Plugin) cacheAndReturn(uuid uuid.UUID, key cacheKey, entry *cacheEntry) (*drone.Config, error) {
var config *drone.Config
if entry.config != "" {
config = &drone.Config{Data: entry.config}
}
// cache the config before we return it, if enabled
if p.cacheTTL > 0 {
p.cache.add(uuid, key, entry, p.cacheTTL)
}
return config, entry.error
}