Skip to content

Commit

Permalink
switch to expirable-cache (didip#86)
Browse files Browse the repository at this point in the history
  • Loading branch information
paskal authored May 24, 2020
1 parent f17d34e commit 3cd4dd2
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 73 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/didip/tollbooth/v5
go 1.12

require (
github.com/patrickmn/go-cache v0.0.0-20170418232947-7ac151875ffb
github.com/go-pkgz/expirable-cache v0.0.3
golang.org/x/net v0.0.0-20161007143504-f4b625ec9b21 // indirect
golang.org/x/time v0.0.0-20160926182426-711ca1cb8763
)
17 changes: 15 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
github.com/patrickmn/go-cache v0.0.0-20170418232947-7ac151875ffb h1:TytdvXWFYkdCn7KS+eNlZULXgc3J9nWzLR/233gWwBw=
github.com/patrickmn/go-cache v0.0.0-20170418232947-7ac151875ffb/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-pkgz/expirable-cache v0.0.3 h1:rTh6qNPp78z0bQE6HDhXBHUwqnV9i09Vm6dksJLXQDc=
github.com/go-pkgz/expirable-cache v0.0.3/go.mod h1:+IauqN00R2FqNRLCLA+X5YljQJrwB179PfiAoMPlTlQ=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
golang.org/x/net v0.0.0-20161007143504-f4b625ec9b21 h1:oOvUY3V+5DQQG3Bgf/tgq5syFCPvlosk3Hm5JFKmDGg=
golang.org/x/net v0.0.0-20161007143504-f4b625ec9b21/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/time v0.0.0-20160926182426-711ca1cb8763 h1:ryh+9pccLWKRcDnumRJGpcEl5IuQKPM5WgAItYcz09Q=
golang.org/x/time v0.0.0-20160926182426-711ca1cb8763/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
86 changes: 21 additions & 65 deletions limiter/limiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"sync"
"time"

gocache "github.com/patrickmn/go-cache"
"github.com/go-pkgz/expirable-cache"
"golang.org/x/time/rate"
)

Expand All @@ -29,25 +29,14 @@ func New(generalExpirableOptions *ExpirableOptions) *Limiter {
lmt.generalExpirableOptions = &ExpirableOptions{}
}

// Default for ExpireJobInterval is every minute.
if lmt.generalExpirableOptions.ExpireJobInterval <= 0 {
lmt.generalExpirableOptions.ExpireJobInterval = time.Minute
}

// Default for DefaultExpirationTTL is 10 years.
if lmt.generalExpirableOptions.DefaultExpirationTTL <= 0 {
lmt.generalExpirableOptions.DefaultExpirationTTL = 87600 * time.Hour
}

lmt.tokenBuckets = gocache.New(
lmt.generalExpirableOptions.DefaultExpirationTTL,
lmt.generalExpirableOptions.ExpireJobInterval,
)
lmt.tokenBuckets, _ = cache.NewCache(cache.TTL(lmt.generalExpirableOptions.DefaultExpirationTTL))

lmt.basicAuthUsers = gocache.New(
lmt.generalExpirableOptions.DefaultExpirationTTL,
lmt.generalExpirableOptions.ExpireJobInterval,
)
lmt.basicAuthUsers, _ = cache.NewCache(cache.TTL(lmt.generalExpirableOptions.DefaultExpirationTTL))

return lmt
}
Expand Down Expand Up @@ -87,17 +76,17 @@ type Limiter struct {
generalExpirableOptions *ExpirableOptions

// List of basic auth usernames to limit.
basicAuthUsers *gocache.Cache
basicAuthUsers cache.Cache

// Map of HTTP headers to limit.
// Empty means skip headers checking.
headers map[string]*gocache.Cache
headers map[string]cache.Cache

// Map of Context values to limit.
contextValues map[string]*gocache.Cache
contextValues map[string]cache.Cache

// Map of limiters with TTL
tokenBuckets *gocache.Cache
tokenBuckets cache.Cache

tokenBucketExpirationTTL time.Duration
basicAuthExpirationTTL time.Duration
Expand Down Expand Up @@ -336,20 +325,13 @@ func (l *Limiter) SetBasicAuthUsers(basicAuthUsers []string) *Limiter {

// GetBasicAuthUsers is thread-safe way of getting list of basic auth usernames to limit.
func (l *Limiter) GetBasicAuthUsers() []string {
asMap := l.basicAuthUsers.Items()

basicAuthUsers := make([]string, 0, len(asMap))
for basicAuthUser := range asMap {
basicAuthUsers = append(basicAuthUsers, basicAuthUser)
}

return basicAuthUsers
return l.basicAuthUsers.Keys()
}

// RemoveBasicAuthUsers is thread-safe way of removing basic auth usernames from existing list.
func (l *Limiter) RemoveBasicAuthUsers(basicAuthUsers []string) *Limiter {
for _, toBeRemoved := range basicAuthUsers {
l.basicAuthUsers.Delete(toBeRemoved)
l.basicAuthUsers.Invalidate(toBeRemoved)
}

return l
Expand All @@ -358,7 +340,7 @@ func (l *Limiter) RemoveBasicAuthUsers(basicAuthUsers []string) *Limiter {
// SetHeaders is thread-safe way of setting map of HTTP headers to limit.
func (l *Limiter) SetHeaders(headers map[string][]string) *Limiter {
if l.headers == nil {
l.headers = make(map[string]*gocache.Cache)
l.headers = make(map[string]cache.Cache)
}

for header, entries := range headers {
Expand All @@ -376,13 +358,7 @@ func (l *Limiter) GetHeaders() map[string][]string {
defer l.RUnlock()

for header, entriesAsGoCache := range l.headers {
entries := make([]string, 0)

for entry := range entriesAsGoCache.Items() {
entries = append(entries, entry)
}

results[header] = entries
results[header] = entriesAsGoCache.Keys()
}

return results
Expand All @@ -400,7 +376,7 @@ func (l *Limiter) SetHeader(header string, entries []string) *Limiter {
}

if !found {
existing = gocache.New(ttl, l.generalExpirableOptions.ExpireJobInterval)
existing, _ = cache.NewCache(cache.TTL(ttl))
}

for _, entry := range entries {
Expand All @@ -420,14 +396,7 @@ func (l *Limiter) GetHeader(header string) []string {
entriesAsGoCache := l.headers[header]
l.RUnlock()

entriesAsMap := entriesAsGoCache.Items()
entries := make([]string, 0)

for entry := range entriesAsMap {
entries = append(entries, entry)
}

return entries
return entriesAsGoCache.Keys()
}

// RemoveHeader is thread-safe way of removing entries of 1 HTTP header.
Expand All @@ -438,7 +407,7 @@ func (l *Limiter) RemoveHeader(header string) *Limiter {
}

l.Lock()
l.headers[header] = gocache.New(ttl, l.generalExpirableOptions.ExpireJobInterval)
l.headers[header], _ = cache.NewCache(cache.TTL(ttl))
l.Unlock()

return l
Expand All @@ -455,7 +424,7 @@ func (l *Limiter) RemoveHeaderEntries(header string, entriesForRemoval []string)
}

for _, toBeRemoved := range entriesForRemoval {
entries.Delete(toBeRemoved)
entries.Invalidate(toBeRemoved)
}

return l
Expand All @@ -464,7 +433,7 @@ func (l *Limiter) RemoveHeaderEntries(header string, entriesForRemoval []string)
// SetContextValues is thread-safe way of setting map of HTTP headers to limit.
func (l *Limiter) SetContextValues(contextValues map[string][]string) *Limiter {
if l.contextValues == nil {
l.contextValues = make(map[string]*gocache.Cache)
l.contextValues = make(map[string]cache.Cache)
}

for contextValue, entries := range contextValues {
Expand All @@ -482,13 +451,7 @@ func (l *Limiter) GetContextValues() map[string][]string {
defer l.RUnlock()

for contextValue, entriesAsGoCache := range l.contextValues {
entries := make([]string, 0)

for entry := range entriesAsGoCache.Items() {
entries = append(entries, entry)
}

results[contextValue] = entries
results[contextValue] = entriesAsGoCache.Keys()
}

return results
Expand All @@ -506,7 +469,7 @@ func (l *Limiter) SetContextValue(contextValue string, entries []string) *Limite
}

if !found {
existing = gocache.New(ttl, l.generalExpirableOptions.ExpireJobInterval)
existing, _ = cache.NewCache(cache.TTL(ttl))
}

for _, entry := range entries {
Expand All @@ -526,14 +489,7 @@ func (l *Limiter) GetContextValue(contextValue string) []string {
entriesAsGoCache := l.contextValues[contextValue]
l.RUnlock()

entriesAsMap := entriesAsGoCache.Items()
entries := make([]string, 0)

for entry := range entriesAsMap {
entries = append(entries, entry)
}

return entries
return entriesAsGoCache.Keys()
}

// RemoveContextValue is thread-safe way of removing entries of 1 Context value.
Expand All @@ -544,7 +500,7 @@ func (l *Limiter) RemoveContextValue(contextValue string) *Limiter {
}

l.Lock()
l.contextValues[contextValue] = gocache.New(ttl, l.generalExpirableOptions.ExpireJobInterval)
l.contextValues[contextValue], _ = cache.NewCache(cache.TTL(ttl))
l.Unlock()

return l
Expand All @@ -561,7 +517,7 @@ func (l *Limiter) RemoveContextValuesEntries(contextValue string, entriesForRemo
}

for _, toBeRemoved := range entriesForRemoval {
entries.Delete(toBeRemoved)
entries.Invalidate(toBeRemoved)
}

return l
Expand Down
2 changes: 1 addition & 1 deletion limiter/limiter_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func BenchmarkLimitReached(b *testing.B) {
}

func BenchmarkLimitReachedWithExpiringBuckets(b *testing.B) {
lmt := New(&ExpirableOptions{DefaultExpirationTTL: time.Minute, ExpireJobInterval: 30 * time.Second}).SetMax(1)
lmt := New(&ExpirableOptions{DefaultExpirationTTL: time.Minute}).SetMax(1)
key := "127.0.0.1|/"

for i := 0; i < b.N; i++ {
Expand Down
1 change: 1 addition & 0 deletions limiter/limiter_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ type ExpirableOptions struct {
DefaultExpirationTTL time.Duration

// How frequently expire job triggers
// Deprecated: not used anymore
ExpireJobInterval time.Duration
}
6 changes: 3 additions & 3 deletions limiter/limiter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestConstructor(t *testing.T) {
}

func TestConstructorExpiringBuckets(t *testing.T) {
lmt := New(&ExpirableOptions{DefaultExpirationTTL: time.Second, ExpireJobInterval: 0}).SetMax(1)
lmt := New(&ExpirableOptions{DefaultExpirationTTL: time.Second}).SetMax(1)
if lmt.GetMax() != 1 {
t.Errorf("Max field is incorrect. Value: %v", lmt.GetMax())
}
Expand Down Expand Up @@ -74,7 +74,7 @@ func TestFloatingLimitReached(t *testing.T) {
}

func TestLimitReachedWithCustomTokenBucketTTL(t *testing.T) {
lmt := New(&ExpirableOptions{DefaultExpirationTTL: time.Second, ExpireJobInterval: 0}).SetMax(1).SetBurst(1)
lmt := New(&ExpirableOptions{DefaultExpirationTTL: time.Second}).SetMax(1).SetBurst(1)
key := "127.0.0.1|/"

if lmt.LimitReached(key) == true {
Expand Down Expand Up @@ -113,7 +113,7 @@ func TestMuchHigherMaxRequests(t *testing.T) {
func TestMuchHigherMaxRequestsWithCustomTokenBucketTTL(t *testing.T) {
numRequests := 1000
delay := (1 * time.Second) / time.Duration(numRequests)
lmt := New(&ExpirableOptions{DefaultExpirationTTL: time.Minute, ExpireJobInterval: time.Minute}).SetMax(float64(numRequests)).SetBurst(1)
lmt := New(&ExpirableOptions{DefaultExpirationTTL: time.Minute}).SetMax(float64(numRequests)).SetBurst(1)
key := "127.0.0.1|/"

for i := 0; i < numRequests; i++ {
Expand Down
2 changes: 1 addition & 1 deletion tollbooth_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func BenchmarkLimitByKeys(b *testing.B) {

func BenchmarkLimitByKeysWithExpiringBuckets(b *testing.B) {
lmt := limiter.New(
&limiter.ExpirableOptions{DefaultExpirationTTL: time.Minute, ExpireJobInterval: time.Minute},
&limiter.ExpirableOptions{DefaultExpirationTTL: time.Minute},
).SetMax(1) // Only 1 request per second is allowed.

for i := 0; i < b.N; i++ {
Expand Down

0 comments on commit 3cd4dd2

Please sign in to comment.