Closed AmitKumarDas closed 2 years ago
// cache // naive caching
// https://blog.chuie.io/posts/synconce/
type QueryClient struct {
cache map[string][]byte
mutex *sync.Mutex
}
// below still has race condition
// race //bug
func (c *QueryClient) DoQuery(name string) []byte {
// Check if the result is already cached.
c.mutex.Lock()
if cached, found := c.cache[name]; found {
c.mutex.Unlock()
return cached, nil
}
c.mutex.Unlock()
// Make the request if it's uncached.
resp, err := http.Get("https://upstream.api/?query=" + url.QueryEscape(name))
// Error handling and resp.Body.Close omitted for brevity.
result, err := ioutil.ReadAll(resp)
// Store the result in the cache.
c.mutex.Lock()
c.cache[name] = result
c.mutex.Unlock()
return result
}
// cache // sync // once
type CacheEntry struct {
data []byte
once *sync.Once
}
type QueryClient struct {
cache map[string]*CacheEntry
mutex *sync.Mutex
}
func (c *QueryClient) DoQuery(name string) []byte {
c.mutex.Lock()
entry, found := c.cache[name]
if !found {
// Create a new entry if one does not exist already.
entry = &CacheEntry{
once: new(sync.Once),
}
c.cache[name] = entry
}
c.mutex.Unlock()
// Now when we invoke `.Do`, if there is an on-going simultaneous operation,
// it will block until it has completed (and `entry.data` is populated).
// Or if the operation has already completed once before,
// this call is a no-op and doesn't block.
entry.once.Do(func() {
resp, err := http.Get("https://upstream.api/?query=" + url.QueryEscape(name))
// Error handling and resp.Body.Close omitted for brevity
entry.data, err = ioutil.ReadAll(resp)
})
return entry.data
}