-
Notifications
You must be signed in to change notification settings - Fork 572
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
Dynamically resizes cache depending on the amount of RAM available (issue #167) #213
Conversation
Codecov Report
@@ Coverage Diff @@
## main #213 +/- ##
==========================================
- Coverage 55.65% 54.35% -1.30%
==========================================
Files 82 83 +1
Lines 3249 3467 +218
==========================================
+ Hits 1808 1884 +76
- Misses 1259 1392 +133
- Partials 182 191 +9
Continue to review full report at Codecov.
|
pkg/storage/cache/cache.go
Outdated
<-cache.cleanupDone | ||
} | ||
|
||
func (cache *Cache) Evit(percent float64) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a typo? I think you meant Evict
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right~ sorry
pkg/storage/storage.go
Outdated
@@ -163,6 +164,42 @@ func New(cfg *config.Config) (*Storage, error) { | |||
return tree.New() | |||
} | |||
|
|||
// load the total memory of the server | |||
vm, err := mem.VirtualMemory() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please add tests for this whole PR?
For tests we could add a way to set this limit arbitrarily, to something like 1 MB, and then make sure the system still works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
already add the test for this PR
pkg/storage/storage.go
Outdated
// start a timer for checking if the memory used by application | ||
// is more than 25% of the total memory, if so, trigger eviction | ||
// with 10% to every cache | ||
go func() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps it would be better to have this as a separate function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea
pkg/storage/storage.go
Outdated
// is more than 25% of the total memory, if so, trigger eviction | ||
// with 10% to every cache | ||
go func() { | ||
ticker := time.NewTimer(interval * time.Second) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a Ticker
is more appropriate here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- The
Timer
type represents a single event - A
Ticker
holds a channel that delivers “ticks” of a clock at intervals
Timers are for when you want to do something once in the future - tickers are for when you want to do something repeatedly at regular intervals.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, but i reset the timer in the loop
// reset the timer
ticker.Reset(interval * time.Second)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For sure that works. However, I think it would be better to use more idiomatic approach with Ticker
:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kolesnikovae I talked with @alonlong about it. I think the idea is that if this procedure takes longer than the timer we want to wait for another X seconds (10 right now I think) before flushing.
So I think it's fine. Although, I wonder if we should just add a time.Sleep there. What do you both think about that? I think that would make code more concise, but maybe there're some downsides I'm not thinking of.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ticker
also has Reset
method for that.
Sorry guys if led you astray. Please don't get me wrong, I was just trying to say that Timer
and Ticker
have different semantics, and for this particular case the last one is more appropriate IMO. Taking into account the mismatch of the variable name and the type it's a bit confusing: is it supposed to be a timer and the variable name should be changed, or is it a ticker indeed and the type should be changed? Both options are okay.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kolesnikovae Got it, I think we can change variable name to timer
pkg/storage/storage.go
Outdated
defer ticker.Stop() | ||
|
||
for range ticker.C { | ||
if s.closing { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this will cause races.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can u help to describe the races?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a race condition on access to closing
field, you should acquire closingMutex
and release it only after Evict
calls. See Close
: basically, I think that we could replace the mutex with an RWMutex
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for range ticker.C {
if s.closing {
return
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is no closingMutex here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, i think for the field closing, the mutex is not necessary. the code is weird for using the mutex for closing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm afraid, without a mutex, there is no other way to avoid the race (without changing too many things): eventually the call will conflict with Close
.
closingMutex
is a member of Storage
:
https://github.com/pyroscope-io/pyroscope/blob/f45b14e491357af26f8a32e989ef573d1b86e8d3/pkg/storage/storage.go#L38-L40
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's a bool variable, i think it's not a problem
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regardless of the type, when the same address accessed for read-write concurrently, a race condition occurs. The funny part is that it would be safer to not check closing
field at all in this particular function, because Evict
and Flush
(in Close
) methods can be called in arbitrary order with no issues :)
…e' into feature/resize_cache
…fter server closes
Raise limits of buffer sizes
Fix the issue: Dynamically resize cache depending on the amount of RAM available #167