Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor eval cache with atomic.Value #402

Merged
merged 1 commit into from
Sep 16, 2020
Merged

Conversation

zhouzhuojie
Copy link
Collaborator

Description

  • Fix "fatal error" when calling Batch Eval with Tags at Volume #398
  • Refactor all the cache with atomic.Value for concurrent access and reduce lock contention
  • Refactor ratelimiter to sync.Map to reduce the rare chance of race condition
  • Fix the logic of merging tags in GetByTags so that we are just merging into the temp variable instead of changing the protected cache

How Has This Been Tested?

  • unit tests
  • integration tests
  • manual tests
  • benchmark

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@zhouzhuojie
Copy link
Collaborator Author

Current benchmark

#!/bin/bash -eo pipefail
make benchmark
PASS
ok  	github.com/checkr/flagr/pkg/config	0.103s
PASS
ok  	github.com/checkr/flagr/pkg/entity	0.256s
goos: linux
goarch: amd64
pkg: github.com/checkr/flagr/pkg/handler
BenchmarkEvalFlag-36           	   39544	     34258 ns/op	    1642 B/op	      36 allocs/op
BenchmarkEvalFlagsByTags-36    	   33512	     32723 ns/op	    1644 B/op	      35 allocs/op
PASS
ok  	github.com/checkr/flagr/pkg/handler	3.436s
?   	github.com/checkr/flagr/pkg/mapper/entity_restapi/e2r	[no test files]
?   	github.com/checkr/flagr/pkg/mapper/entity_restapi/r2e	[no test files]
PASS
ok  	github.com/checkr/flagr/pkg/util	0.031s
CircleCI received exit code 0

rateLimitMap[flagID] = rl
}
if !rl.Limit() {
rl, _ := rateLimitMap.LoadOrStore(flagID, ratelimit.New(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure how important this is, but this will always create a new rate limiter, even if one already exists.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ratelimit.New is pretty fast, probably faster than we do a Load() and checks ok. All primitive operation code here:

https://github.com/bsm/ratelimit/blob/master/ratelimit.go#L32-L49

ec.idCache = idCache
ec.keyCache = keyCache
ec.tagCache = tagCache
ec.cache.Store(&cacheContainer{
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iiuc this is called from Start(). Do you expect Start() do be called concurrently? If not, why is the atomic needed here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Start() will call it once, however, there's a cron goroutinue also periodically updates the cache when the cache is heavily being read, so atomic is used here. Previously this is locked by RWMutex.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it update the cache's values or replaces the entire object?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replaces the whole object

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool

Comment on lines +66 to +69
fSet, ok := cache.tagCache[t]
if ok {
for ia, va := range results {
f[ia] = va
for fID, f := range fSet {
results[fID] = f
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, this is the change that fixes #398

@zhouzhuojie zhouzhuojie merged commit 2c35ad8 into master Sep 16, 2020
@zhouzhuojie zhouzhuojie deleted the zz/refactor-eval-cache branch September 16, 2020 23:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

"fatal error" when calling Batch Eval with Tags at Volume
3 participants