From f053007954e43a5553a239d3ab3065c163d60090 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 24 Dec 2013 12:43:19 -0800 Subject: [PATCH] geocode: cache and dup-suppress lookups Change-Id: I600b9d9957ea74d4b91d0b162c7de55d643e0ee9 --- pkg/geocode/geocode.go | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/pkg/geocode/geocode.go b/pkg/geocode/geocode.go index ef98cb64f..6a8ce123d 100644 --- a/pkg/geocode/geocode.go +++ b/pkg/geocode/geocode.go @@ -22,8 +22,10 @@ import ( "io" "net/http" "net/url" + "sync" "camlistore.org/pkg/context" + "camlistore.org/pkg/singleflight" ) type LatLong struct { @@ -36,17 +38,43 @@ type Rect struct { SouthWest LatLong `json:"southwest"` } +var ( + mu sync.RWMutex + cache = map[string][]Rect{} + + sf singleflight.Group +) + // Lookup returns rectangles for the given address. Currently the only // implementation is the Google geocoding service. func Lookup(ctx *context.Context, address string) ([]Rect, error) { - // TODO: static data files from OpenStreetMap, Wikipedia, etc? - urlStr := "https://maps.googleapis.com/maps/api/geocode/json?address=" + url.QueryEscape(address) + "&sensor=false" - res, err := http.Get(urlStr) + mu.RLock() + rects, ok := cache[address] + mu.RUnlock() + if ok { + return rects, nil + } + + rectsi, err := sf.Do(address, func() (interface{}, error) { + // TODO: static data files from OpenStreetMap, Wikipedia, etc? + urlStr := "https://maps.googleapis.com/maps/api/geocode/json?address=" + url.QueryEscape(address) + "&sensor=false" + res, err := http.Get(urlStr) + if err != nil { + return nil, err + } + defer res.Body.Close() + rects, err := decodeGoogleResponse(res.Body) + if err == nil { + mu.Lock() + cache[address] = rects + mu.Unlock() + } + return rects, err + }) if err != nil { return nil, err } - defer res.Body.Close() - return decodeGoogleResponse(res.Body) + return rectsi.([]Rect), nil } type googleResTop struct {