40
40
// Instead, we move items from old to new when they're accessed
41
41
// and throw away the old map at refresh time.
42
42
old, new map[Key]entry
44
inFlight map[Key]*fetchCall
47
// fetch represents an in-progress fetch call. If a cache Get request
48
// is made for an item that is currently being fetched, this will
49
// be used to avoid an extra call to the fetch function.
50
type fetchCall struct {
45
56
// New returns a new Cache that will cache items for
91
103
if val, ok := c.cachedValue(key, now); ok {
107
if f, ok := c.inFlight[key]; ok {
108
// There's already an in-flight request for the key, so wait
109
// for that to complete and use its results.
112
// The value will have been added to the cache by the first fetch,
113
// so no need to add it here.
117
return nil, errgo.Mask(f.err, errgo.Any)
122
// Mark the request as done when we return, and after
123
// the value has been added to the cache.
94
126
// Fetch the data without the mutex held
95
127
// so that one slow fetch doesn't hold up
96
128
// all the other cache accesses.
97
130
val, err := fetch()
99
// TODO consider caching cache misses.
100
return nil, errgo.Mask(err, errgo.Any)
102
if c.maxAge < 2*time.Nanosecond {
134
// Set the result in the fetchCall so that other calls can see it.
135
f.val, f.err = val, err
136
if err == nil && c.maxAge >= 2*time.Nanosecond {
103
137
// If maxAge is < 2ns then the expiry code will panic because the
104
138
// actual expiry time will be maxAge - a random value in the
105
139
// interval [0, maxAge/2). If maxAge is < 2ns then this requires
108
142
// This value is so small that there's no need to cache anyway,
109
143
// which makes tests more obviously deterministic when using
110
144
// a zero expiry time.
115
// Add the new cache entry. Because it's quite likely that a
116
// large number of cache entries will be initially fetched at
117
// the same time, we want to avoid a thundering herd of fetches
118
// when they all expire at the same time, so we set the expiry
119
// time to a random interval between [now + t.maxAge/2, now +
120
// t.maxAge] and so they'll be spread over time without
121
// compromising the maxAge value.
124
expire: now.Add(c.maxAge - time.Duration(rand.Int63n(int64(c.maxAge/2)))),
147
expire: now.Add(c.maxAge - time.Duration(rand.Int63n(int64(c.maxAge/2)))),
150
delete(c.inFlight, key)
154
return nil, errgo.Mask(f.err, errgo.Any)
129
157
// cachedValue returns any cached value for the given key