diff --git a/cache.go b/cache.go index 7a6bd8b..f42b378 100644 --- a/cache.go +++ b/cache.go @@ -3,6 +3,7 @@ package main import ( "bytes" "crypto/sha256" + "encoding/binary" "fmt" "io" "net/http" @@ -11,9 +12,10 @@ import ( "strconv" "strings" "time" + "unsafe" "github.com/araddon/dateparse" - lru "github.com/hashicorp/golang-lru" + "github.com/dgraph-io/ristretto" servertiming "github.com/mitchellh/go-server-timing" "golang.org/x/sync/singleflight" ) @@ -24,11 +26,29 @@ const ( var ( cacheGroup singleflight.Group - cacheLru *lru.Cache + cacheR *ristretto.Cache ) func initCache() (err error) { - cacheLru, err = lru.New(500) + cacheR, err = ristretto.NewCache(&ristretto.Config{ + NumCounters: 5000, + MaxCost: 20000000, // 20 MB + BufferItems: 16, + Cost: func(value interface{}) (cost int64) { + if cacheItem, ok := value.(*cacheItem); ok { + cost = int64(binary.Size(cacheItem.body)) // Byte size of body + for h, hv := range cacheItem.header { + cost += int64(binary.Size([]byte(h))) // Byte size of header name + for _, hvi := range hv { + cost += int64(binary.Size([]byte(hvi))) // byte size of each header value item + } + } + } else { + cost = int64(unsafe.Sizeof(cacheItem)) + } + return cost + }, + }) return } @@ -124,18 +144,11 @@ type cacheItem struct { body []byte } -func (c *cacheItem) expired() bool { - if c.expiration != 0 { - return time.Now().After(c.creationTime.Add(time.Duration(c.expiration) * time.Second)) - } - return false -} - func getCache(key string, next http.Handler, r *http.Request) (item *cacheItem) { - if lruItem, ok := cacheLru.Get(key); ok { - item = lruItem.(*cacheItem) + if rItem, ok := cacheR.Get(key); ok { + item = rItem.(*cacheItem) } - if item == nil || item.expired() { + if item == nil { // No cache available servertiming.FromContext(r.Context()).NewMetric("cm") // Remove problematic headers @@ -182,7 +195,12 @@ func getCache(key string, next http.Handler, r *http.Request) (item *cacheItem) } // Save cache if cch := item.header.Get("Cache-Control"); !strings.Contains(cch, "no-store") && !strings.Contains(cch, "private") && !strings.Contains(cch, "no-cache") { - cacheLru.Add(key, item) + if exp == 0 { + cacheR.Set(key, item, 0) + } else { + ttl := time.Duration(exp) * time.Second + cacheR.SetWithTTL(key, item, 0, ttl) + } } } else { servertiming.FromContext(r.Context()).NewMetric("c") @@ -191,7 +209,7 @@ func getCache(key string, next http.Handler, r *http.Request) (item *cacheItem) } func purgeCache() { - cacheLru.Purge() + cacheR.Clear() } func setInternalCacheExpirationHeader(w http.ResponseWriter, expiration int) { diff --git a/go.mod b/go.mod index 27b0e76..4bec0ea 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/boombuler/barcode v1.0.1 // indirect github.com/caddyserver/certmagic v0.12.0 github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f + github.com/dgraph-io/ristretto v0.0.4-0.20210311064603-e4f298c8aa88 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/elnormous/contenttype v0.0.0-20210110050721-79150725153f github.com/go-chi/chi/v5 v5.0.1 @@ -21,7 +22,6 @@ require ( github.com/gopherjs/gopherjs v0.0.0-20210202160940-bed99a852dfe // indirect github.com/gorilla/feeds v1.1.1 github.com/gorilla/handlers v1.5.1 - github.com/hashicorp/golang-lru v0.5.4 github.com/jonboulle/clockwork v0.2.2 // indirect github.com/joncrlsn/dque v0.0.0-20200702023911-3e80e3146ce5 github.com/klauspost/cpuid v1.3.1 // indirect @@ -49,7 +49,7 @@ require ( github.com/spf13/viper v1.7.1 github.com/tdewolff/minify/v2 v2.9.13 github.com/tdewolff/parse/v2 v2.5.12 // indirect - github.com/thoas/go-funk v0.7.1-0.20201128100912-5035611e402b + github.com/thoas/go-funk v0.8.0 github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 github.com/vcraescu/go-paginator v1.0.1-0.20201114172518-2cfc59fe05c2 github.com/yuin/goldmark v1.3.2 diff --git a/go.sum b/go.sum index 0cd9ae0..7276fe1 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,7 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= github.com/PuerkitoBio/goquery v1.6.1 h1:FgjbQZKl5HTmcn4sKBgvx8vv63nhyhIpv7lJpFGCWpk= @@ -44,6 +45,7 @@ github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= github.com/caddyserver/certmagic v0.12.0 h1:1f7kxykaJkOVVpXJ8ZrC6RAO5F6+kKm9U7dBFbLNeug= github.com/caddyserver/certmagic v0.12.0/go.mod h1:tr26xh+9fY5dN0J6IPAlMj07qpog22PJKa7Nw7j835U= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU= @@ -60,9 +62,14 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f h1:q/DpyjJjZs94bziQ7YkBmIlpqbVP7yw179rnzoNVX1M= github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f/go.mod h1:QGrK8vMWWHQYQ3QU9bw9Y9OPNfxccGzfb41qjvVeXtY= +github.com/dgraph-io/ristretto v0.0.4-0.20210311064603-e4f298c8aa88 h1:a13o656FuUv6beRVDMZqN6D/Cw8SjL02TT3yuV4UeTo= +github.com/dgraph-io/ristretto v0.0.4-0.20210311064603-e4f298c8aa88/go.mod h1:MIonLggsKgZLUSt414ExgwNtlOL5MuEoAJP514mwGe8= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/elnormous/contenttype v0.0.0-20210110050721-79150725153f h1:juwLa2Kbp2uwOGMOagrkTYXN/5+7sbINMmIZSluH2Gc= github.com/elnormous/contenttype v0.0.0-20210110050721-79150725153f/go.mod h1:ngVcyGGU8pnn4QJ5sL4StrNgc/wmXZXy5IQSBuHOFPg= @@ -152,8 +159,6 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v0.0.0-20170914154624-68e816d1c783/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= @@ -288,6 +293,7 @@ github.com/snabb/diagio v1.0.0/go.mod h1:ZyGaWFhfBVqstGUw6laYetzeTwZ2xxVPqTALx1Q github.com/snabb/sitemap v1.0.0 h1:7vJeNPAaaj7fQSRS3WYuJHzUjdnhLdSLLpvVtnhbzC0= github.com/snabb/sitemap v1.0.0/go.mod h1:Id8uz1+WYdiNmSjEi4BIvL5UwNPYLsTHzRbjmDwNDzA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v0.0.0-20170901052352-ee1bd8ee15a1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -324,8 +330,8 @@ github.com/tdewolff/parse/v2 v2.5.12 h1:Dxblj0AftHJ3bwBmKdAd7O1wB1+CVFI/BCaYaGuu github.com/tdewolff/parse/v2 v2.5.12/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho= github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4= github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= -github.com/thoas/go-funk v0.7.1-0.20201128100912-5035611e402b h1:EBnJBNE7sw2Z7dg2inKlTQNO2se7PvDejZQjNaPAjg8= -github.com/thoas/go-funk v0.7.1-0.20201128100912-5035611e402b/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= +github.com/thoas/go-funk v0.8.0 h1:JP9tKSvnpFVclYgDM0Is7FD9M4fhPvqA0s0BsXmzSRQ= +github.com/thoas/go-funk v0.8.0/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=